Skip to content

Commit 2d36945

Browse files
authored
Merge pull request #1197 from AudricV/yt_innertube-clients-changes-for-streams
[YouTube] Workaround HTTP 403s on streaming URLs of WEB client (after some time or instantly for some JavaScript players), update clients info
2 parents 312e910 + d73de6b commit 2d36945

394 files changed

Lines changed: 30544 additions & 28813 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ private YoutubeParsingHelper() {
152152
* The client version for InnerTube requests with the {@code WEB} client, used as the last
153153
* fallback if the extraction of the real one failed.
154154
*/
155-
private static final String HARDCODED_CLIENT_VERSION = "2.20240410.01.00";
155+
private static final String HARDCODED_CLIENT_VERSION = "2.20240718.01.00";
156156

157157
/**
158158
* The hardcoded client version of the Android app used for InnerTube requests with this
@@ -163,7 +163,7 @@ private YoutubeParsingHelper() {
163163
* such as <a href="https://www.apkmirror.com/apk/google-inc/youtube/">APKMirror</a>.
164164
* </p>
165165
*/
166-
private static final String ANDROID_YOUTUBE_CLIENT_VERSION = "19.13.36";
166+
private static final String ANDROID_YOUTUBE_CLIENT_VERSION = "19.28.35";
167167

168168
/**
169169
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
@@ -174,7 +174,7 @@ private YoutubeParsingHelper() {
174174
* Store page of the YouTube app</a>, in the {@code What’s New} section.
175175
* </p>
176176
*/
177-
private static final String IOS_YOUTUBE_CLIENT_VERSION = "19.14.3";
177+
private static final String IOS_YOUTUBE_CLIENT_VERSION = "19.28.1";
178178

179179
/**
180180
* The hardcoded client version used for InnerTube requests with the TV HTML5 embed client.
@@ -190,7 +190,7 @@ private YoutubeParsingHelper() {
190190
* The hardcoded client version used for InnerTube requests with the YouTube Music desktop
191191
* client.
192192
*/
193-
private static final String HARDCODED_YOUTUBE_MUSIC_CLIENT_VERSION = "1.20240403.01.00";
193+
private static final String HARDCODED_YOUTUBE_MUSIC_CLIENT_VERSION = "1.20240715.01.00";
194194

195195
private static String clientVersion;
196196

@@ -219,31 +219,31 @@ private YoutubeParsingHelper() {
219219
* information.
220220
* </p>
221221
*/
222-
private static final String IOS_DEVICE_MODEL = "iPhone15,4";
222+
private static final String IOS_DEVICE_MODEL = "iPhone16,2";
223223

224224
/**
225-
* Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app. To be
226-
* used for the {@code "osVersion"} field in JSON POST requests.
225+
* Spoofing an iPhone 15 Pro Max running iOS 17.5.1 with the hardcoded version of the iOS app.
226+
* To be used for the {@code "osVersion"} field in JSON POST requests.
227227
* <p>
228228
* The value of this field seems to use the following structure:
229229
* "iOS major version.minor version.patch version.build version", where
230230
* "patch version" is equal to 0 if it isn't set
231231
* The build version corresponding to the iOS version used can be found on
232-
* <a href="https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15">
233-
* https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15</a>
232+
* <a href="https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15_Pro_Max">
233+
* https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15_Pro_Max</a>
234234
* </p>
235235
*
236236
* @see #IOS_USER_AGENT_VERSION
237237
*/
238-
private static final String IOS_OS_VERSION = "17.4.1.21E237";
238+
private static final String IOS_OS_VERSION = "17.5.1.21F90";
239239

240240
/**
241-
* Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app. To be
241+
* Spoofing an iPhone 15 running iOS 17.5.1 with the hardcoded version of the iOS app. To be
242242
* used in the user agent for requests.
243243
*
244244
* @see #IOS_OS_VERSION
245245
*/
246-
private static final String IOS_USER_AGENT_VERSION = "17_4_1";
246+
private static final String IOS_USER_AGENT_VERSION = "17_5_1";
247247

248248
private static Random numberGenerator = new Random();
249249

@@ -1301,31 +1301,49 @@ public static JsonBuilder<JsonObject> prepareTvHtml5EmbedJsonBuilder(
13011301
}
13021302

13031303
@Nonnull
1304-
public static byte[] createDesktopPlayerBody(
1304+
public static JsonObject getWebPlayerResponse(
1305+
@Nonnull final Localization localization,
1306+
@Nonnull final ContentCountry contentCountry,
1307+
@Nonnull final String videoId) throws IOException, ExtractionException {
1308+
final byte[] body = JsonWriter.string(
1309+
prepareDesktopJsonBuilder(localization, contentCountry)
1310+
.value(VIDEO_ID, videoId)
1311+
.value(CONTENT_CHECK_OK, true)
1312+
.value(RACY_CHECK_OK, true)
1313+
.done())
1314+
.getBytes(StandardCharsets.UTF_8);
1315+
final String url = YOUTUBEI_V1_URL + "player" + "?" + DISABLE_PRETTY_PRINT_PARAMETER
1316+
+ "&$fields=microformat,playabilityStatus,storyboards,videoDetails";
1317+
1318+
return JsonUtils.toJsonObject(getValidJsonResponseBody(
1319+
getDownloader().postWithContentTypeJson(
1320+
url, getYouTubeHeaders(), body, localization)));
1321+
}
1322+
1323+
@Nonnull
1324+
public static byte[] createTvHtml5EmbedPlayerBody(
13051325
@Nonnull final Localization localization,
13061326
@Nonnull final ContentCountry contentCountry,
13071327
@Nonnull final String videoId,
13081328
@Nonnull final Integer sts,
1309-
final boolean isTvHtml5DesktopJsonBuilder,
1310-
@Nonnull final String contentPlaybackNonce) throws IOException, ExtractionException {
1329+
@Nonnull final String contentPlaybackNonce) {
13111330
// @formatter:off
1312-
return JsonWriter.string((isTvHtml5DesktopJsonBuilder
1313-
? prepareTvHtml5EmbedJsonBuilder(localization, contentCountry, videoId)
1314-
: prepareDesktopJsonBuilder(localization, contentCountry))
1315-
.object("playbackContext")
1316-
.object("contentPlaybackContext")
1317-
// Signature timestamp from the JavaScript base player is needed to get
1318-
// working obfuscated URLs
1319-
.value("signatureTimestamp", sts)
1320-
.value("referer", "https://www.youtube.com/watch?v=" + videoId)
1331+
return JsonWriter.string(
1332+
prepareTvHtml5EmbedJsonBuilder(localization, contentCountry, videoId)
1333+
.object("playbackContext")
1334+
.object("contentPlaybackContext")
1335+
// Signature timestamp from the JavaScript base player is needed to get
1336+
// working obfuscated URLs
1337+
.value("signatureTimestamp", sts)
1338+
.value("referer", "https://www.youtube.com/watch?v=" + videoId)
1339+
.end()
13211340
.end()
1322-
.end()
1323-
.value(CPN, contentPlaybackNonce)
1324-
.value(VIDEO_ID, videoId)
1325-
.value(CONTENT_CHECK_OK, true)
1326-
.value(RACY_CHECK_OK, true)
1327-
.done())
1328-
.getBytes(StandardCharsets.UTF_8);
1341+
.value(CPN, contentPlaybackNonce)
1342+
.value(VIDEO_ID, videoId)
1343+
.value(CONTENT_CHECK_OK, true)
1344+
.value(RACY_CHECK_OK, true)
1345+
.done())
1346+
.getBytes(StandardCharsets.UTF_8);
13291347
// @formatter:on
13301348
}
13311349

@@ -1366,7 +1384,7 @@ public static String getAndroidUserAgent(@Nullable final Localization localizati
13661384
*/
13671385
@Nonnull
13681386
public static String getIosUserAgent(@Nullable final Localization localization) {
1369-
// Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app
1387+
// Spoofing an iPhone 15 running iOS 17.5.1 with the hardcoded version of the iOS app
13701388
return "com.google.ios.youtube/" + IOS_YOUTUBE_CLIENT_VERSION
13711389
+ "(" + IOS_DEVICE_MODEL + "; U; CPU iOS "
13721390
+ IOS_USER_AGENT_VERSION + " like Mac OS X; "

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

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,54 @@ final class YoutubeThrottlingParameterUtils {
2626

2727
private static final String ARRAY_ACCESS_REGEX = "\\[(\\d+)]";
2828

29-
/**
30-
* The first regex matches this, where we want BDa:
31-
* <p>
32-
* (b=String.fromCharCode(110),c=a.get(b))&&(c=<strong>BDa</strong><strong>[0]</strong>(c)
33-
* <p>
34-
* Array access is optional, but needs to be handled, since the actual function is inside the
35-
* array.
36-
*/
3729
// CHECKSTYLE:OFF
3830
private static final Pattern[] DEOBFUSCATION_FUNCTION_NAME_REGEXES = {
31+
32+
/*
33+
* The first regex matches the following text, where we want rDa and the array index
34+
* accessed:
35+
*
36+
* a.D&&(b="nn"[+a.D],c=a.get(b))&&(c=rDa[0](c),a.set(b,c),rDa.length||rma("")
37+
*/
38+
Pattern.compile(SINGLE_CHAR_VARIABLE_REGEX + "+=\"nn\"\\[\\+"
39+
+ SINGLE_CHAR_VARIABLE_REGEX + "+\\." + SINGLE_CHAR_VARIABLE_REGEX + "+],"
40+
+ SINGLE_CHAR_VARIABLE_REGEX + "+=" + SINGLE_CHAR_VARIABLE_REGEX
41+
+ "+\\.get\\(" + SINGLE_CHAR_VARIABLE_REGEX + "+\\)\\)&&\\("
42+
+ SINGLE_CHAR_VARIABLE_REGEX + "+=(" + SINGLE_CHAR_VARIABLE_REGEX
43+
+ "+)\\[(\\d+)]"),
44+
45+
/*
46+
* The second regex matches the following text, where we want rma:
47+
*
48+
* a.D&&(b="nn"[+a.D],c=a.get(b))&&(c=rDa[0](c),a.set(b,c),rDa.length||rma("")
49+
*/
50+
Pattern.compile(SINGLE_CHAR_VARIABLE_REGEX + "+=\"nn\"\\[\\+"
51+
+ SINGLE_CHAR_VARIABLE_REGEX + "+\\." + SINGLE_CHAR_VARIABLE_REGEX + "+],"
52+
+ SINGLE_CHAR_VARIABLE_REGEX + "+=" + SINGLE_CHAR_VARIABLE_REGEX + "+\\.get\\("
53+
+ SINGLE_CHAR_VARIABLE_REGEX + "+\\)\\).+\\|\\|(" + SINGLE_CHAR_VARIABLE_REGEX
54+
+ "+)\\(\"\"\\)"),
55+
56+
/*
57+
* The third regex matches the following text, where we want BDa and the array index
58+
* accessed:
59+
*
60+
* (b=String.fromCharCode(110),c=a.get(b))&&(c=BDa[0](c)
61+
*/
3962
Pattern.compile("\\(" + SINGLE_CHAR_VARIABLE_REGEX + "=String\\.fromCharCode\\(110\\),"
4063
+ SINGLE_CHAR_VARIABLE_REGEX + "=" + SINGLE_CHAR_VARIABLE_REGEX + "\\.get\\("
4164
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)\\)" + "&&\\(" + SINGLE_CHAR_VARIABLE_REGEX
4265
+ "=(" + FUNCTION_NAME_REGEX + ")" + "(?:" + ARRAY_ACCESS_REGEX + ")?\\("
4366
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)"),
67+
68+
/*
69+
* The fourth regex matches the following text, where we want Yva and the array index
70+
* accessed:
71+
*
72+
* .get("n"))&&(b=Yva[0](b)
73+
*/
4474
Pattern.compile("\\.get\\(\"n\"\\)\\)&&\\(" + SINGLE_CHAR_VARIABLE_REGEX
4575
+ "=(" + FUNCTION_NAME_REGEX + ")(?:" + ARRAY_ACCESS_REGEX + ")?\\("
46-
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)"),
76+
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)")
4777
};
4878
// CHECKSTYLE:ON
4979

0 commit comments

Comments
 (0)