diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java
index 9a811737a..0f97bd12a 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java
@@ -48,6 +48,7 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.AudioTrackType;
import org.schabi.newpipe.extractor.utils.JsonUtils;
import org.schabi.newpipe.extractor.utils.Parser;
+import org.schabi.newpipe.extractor.utils.ProtoBuilder;
import org.schabi.newpipe.extractor.utils.RandomStringFromAlphabetGenerator;
import org.schabi.newpipe.extractor.utils.Utils;
@@ -212,7 +213,7 @@ public final class YoutubeParsingHelper {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
- * The device machine id for the iPhone 15, used to get 60fps with the {@code iOS} client.
+ * The device machine id for the iPhone 16, used to get 60fps with the {@code iOS} client.
*
*
* See this GitHub Gist for more
@@ -222,15 +223,15 @@ public final class YoutubeParsingHelper {
private static final String IOS_DEVICE_MODEL = "iPhone16,2";
/**
- * Spoofing an iPhone 15 Pro Max running iOS 17.5.1 with the hardcoded version of the iOS app.
+ * Spoofing an iPhone 16 Pro Max running iOS 18.1.0 with the hardcoded version of the iOS app.
* To be used for the {@code "osVersion"} field in JSON POST requests.
*
* The value of this field seems to use the following structure:
* "iOS major version.minor version.patch version.build version", where
* "patch version" is equal to 0 if it isn't set
* The build version corresponding to the iOS version used can be found on
- *
- * https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15_Pro_Max
+ *
+ * https://theapplewiki.com/wiki/Firmware/iPhone/18.x#iPhone_16_Pro_Max
*
*
* @see #IOS_USER_AGENT_VERSION
@@ -238,7 +239,7 @@ public final class YoutubeParsingHelper {
private static final String IOS_OS_VERSION = "18.1.0.22B83";
/**
- * Spoofing an iPhone 15 running iOS 17.5.1 with the hardcoded version of the iOS app. To be
+ * Spoofing an iPhone 16 Pro Max running iOS 18.1.0 with the hardcoded version of the iOS app. To be
* used in the user agent for requests.
*
* @see #IOS_OS_VERSION
@@ -306,7 +307,7 @@ public final class YoutubeParsingHelper {
public static String randomVisitorData(final ContentCountry country) {
final ProtoBuilder pbE2 = new ProtoBuilder();
pbE2.string(2, "");
- pbE2.varint(4, numberGenerator.nextInt(1, 256));
+ pbE2.varint(4, numberGenerator.nextInt(255) + 1);
final ProtoBuilder pbE = new ProtoBuilder();
pbE.string(1, country.getCountryCode());
@@ -1181,10 +1182,11 @@ public final class YoutubeParsingHelper {
public static JsonBuilder prepareDesktopJsonBuilder(
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry,
- @Nullable String visitorData)
+ @Nullable final String visitorData)
throws IOException, ExtractionException {
- if (visitorData == null) {
- visitorData = randomVisitorData(contentCountry);
+ String vData = visitorData;
+ if (vData == null) {
+ vData = randomVisitorData(contentCountry);
}
// @formatter:off
@@ -1198,7 +1200,7 @@ public final class YoutubeParsingHelper {
.value("originalUrl", "https://www.youtube.com")
.value("platform", "DESKTOP")
.value("utcOffsetMinutes", 0)
- .value("visitorData", visitorData)
+ .value("visitorData", vData)
.end()
.object("request")
.array("internalExperimentFlags")
@@ -1410,7 +1412,7 @@ public final class YoutubeParsingHelper {
*/
@Nonnull
public static String getIosUserAgent(@Nullable final Localization localization) {
- // Spoofing an iPhone 15 running iOS 17.5.1 with the hardcoded version of the iOS app
+ // Spoofing an iPhone 16 Pro Max running iOS 17.5.1 with the hardcoded version of the iOS app
return "com.google.ios.youtube/" + IOS_YOUTUBE_CLIENT_VERSION
+ "(" + IOS_DEVICE_MODEL + "; U; CPU iOS "
+ IOS_USER_AGENT_VERSION + " like Mac OS X; "
diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ProtoBuilder.java b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ProtoBuilder.java
similarity index 82%
rename from extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ProtoBuilder.java
rename to extractor/src/main/java/org/schabi/newpipe/extractor/utils/ProtoBuilder.java
index 01368ca78..f0e223a9c 100644
--- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/ProtoBuilder.java
+++ b/extractor/src/main/java/org/schabi/newpipe/extractor/utils/ProtoBuilder.java
@@ -1,4 +1,4 @@
-package org.schabi.newpipe.extractor.services.youtube;
+package org.schabi.newpipe.extractor.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -22,22 +22,23 @@ public class ProtoBuilder {
return URLEncoder.encode(b64, StandardCharsets.UTF_8);
}
- private void writeVarint(long val) {
+ private void writeVarint(final long val) {
try {
if (val == 0) {
byteBuffer.write(new byte[]{(byte) 0});
} else {
- while (val != 0) {
- byte b = (byte) (val & 0x7f);
- val >>= 7;
+ long v = val;
+ while (v != 0) {
+ byte b = (byte) (v & 0x7f);
+ v >>= 7;
- if (val != 0) {
+ if (v != 0) {
b |= (byte) 0x80;
}
byteBuffer.write(new byte[]{b});
}
}
- } catch (IOException e) {
+ } catch (final IOException e) {
throw new RuntimeException(e);
}
}
@@ -64,7 +65,7 @@ public class ProtoBuilder {
writeVarint(bytes.length);
try {
byteBuffer.write(bytes);
- } catch (IOException e) {
+ } catch (final IOException e) {
throw new RuntimeException(e);
}
}
diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/utils/ProtoBuilderTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/utils/ProtoBuilderTest.java
new file mode 100644
index 000000000..b39879451
--- /dev/null
+++ b/extractor/src/test/java/org/schabi/newpipe/extractor/utils/ProtoBuilderTest.java
@@ -0,0 +1,18 @@
+package org.schabi.newpipe.extractor.utils;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ProtoBuilderTest {
+ @Test
+ public void testProtoBuilder() {
+ final ProtoBuilder pb = new ProtoBuilder();
+ pb.varint(1, 128);
+ pb.varint(2, 1234567890);
+ pb.varint(3, 1234567890123456789L);
+ pb.string(4, "Hello");
+ pb.bytes(5, new byte[]{1, 2, 3});
+ assertEquals("CIABENKF2MwEGJWCpu_HnoSRESIFSGVsbG8qAwECAw%3D%3D", pb.toUrlencodedBase64());
+ }
+}