Skip to content

Commit

Permalink
Update iOS client and add random visitor data to requests (#865)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ales315 authored Jan 25, 2025
1 parent 8c81f14 commit 5690324
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 6 deletions.
81 changes: 81 additions & 0 deletions YoutubeExplode/Utils/ProtoBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.IO;
using System.Text;

namespace YoutubeExplode.Utils
{
internal class ProtoBuilder
{
private MemoryStream _byteBuffer;

public ProtoBuilder()
{
_byteBuffer = new MemoryStream();
}

public byte[] ToBytes()
{
return _byteBuffer.ToArray();
}

public string ToUrlencodedBase64()
{
var b64 = Convert
.ToBase64String(ToBytes())
.Replace('+', '-')
.Replace('/', '_')
.TrimEnd('=');
return Uri.EscapeDataString(b64);
}

private void WriteVarint(long val)
{
if (val == 0)
{
_byteBuffer.WriteByte(0);
}
else
{
long v = val;
while (v != 0)
{
byte b = (byte)(v & 0x7F);
v >>= 7;

if (v != 0)
{
b |= 0x80;
}
_byteBuffer.WriteByte(b);
}
}
}

private void Field(int field, byte wire)
{
long fbits = ((long)field) << 3;
long wbits = ((long)wire) & 0x07;
long val = fbits | wbits;
WriteVarint(val);
}

public void Varint(int field, long val)
{
Field(field, 0);
WriteVarint(val);
}

public void String(int field, string str)
{
var strBytes = Encoding.UTF8.GetBytes(str);
Bytes(field, strBytes);
}

public void Bytes(int field, byte[] bytes)
{
Field(field, 2);
WriteVarint(bytes.Length);
_byteBuffer.Write(bytes, 0, bytes.Length);
}
}
}
45 changes: 45 additions & 0 deletions YoutubeExplode/Utils/YoutubeParsingHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace YoutubeExplode.Utils
{
internal static class YoutubeParsingHelper
{
private static string CONTENT_PLAYBACK_NONCE_ALPHABET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

public static string GetRandomVisitorData()
{
Random r = new Random();
ProtoBuilder pbE2 = new ProtoBuilder();
pbE2.String(2, "");
pbE2.Varint(4, r.Next(255) + 1);

ProtoBuilder pbE = new ProtoBuilder();
pbE.String(1, "US");
pbE.Bytes(2, pbE2.ToBytes());

ProtoBuilder pb = new ProtoBuilder();
pb.String(1, GenerateRandomStringFromAlphabet(CONTENT_PLAYBACK_NONCE_ALPHABET, 11, r));
pb.Varint(5, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000 - r.Next(600000));
pb.Bytes(6, pbE.ToBytes());
return pb.ToUrlencodedBase64();
}

private static string GenerateRandomStringFromAlphabet(
string alphabet,
int length,
Random random
)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++)
{
sb.Append(alphabet.ElementAt(random.Next(alphabet.Length)));
}
return sb.ToString();
}
}
}
17 changes: 11 additions & 6 deletions YoutubeExplode/Videos/VideoController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ internal class VideoController(HttpClient http)
{
protected HttpClient Http { get; } = http;

private string _visitorData = null!;

public async ValueTask<VideoWatchPage> GetVideoWatchPageAsync(
VideoId videoId,
CancellationToken cancellationToken = default
Expand Down Expand Up @@ -61,6 +63,9 @@ public async ValueTask<PlayerResponse> GetPlayerResponseAsync(
"https://www.youtube.com/youtubei/v1/player"
);

if (_visitorData == null)
_visitorData = YoutubeParsingHelper.GetRandomVisitorData();

request.Content = new StringContent(
// lang=json
$$"""
Expand All @@ -70,14 +75,14 @@ public async ValueTask<PlayerResponse> GetPlayerResponseAsync(
"context": {
"client": {
"clientName": "IOS",
"clientVersion": "19.29.1",
"clientVersion": "19.45.4",
"deviceMake": "Apple",
"deviceModel": "iPhone16,2",
"platform": "MOBILE",
"osName": "IOS",
"osVersion": "18.1.0.22B83",
"visitorData": {{Json.Serialize(_visitorData)}},
"hl": "en",
"osName": "iPhone",
"osVersion": "17.5.1.21F90",
"timeZone": "UTC",
"userAgent": "com.google.ios.youtube/19.29.1 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X;)",
"gl": "US",
"utcOffsetMinutes": 0
}
Expand All @@ -90,7 +95,7 @@ public async ValueTask<PlayerResponse> GetPlayerResponseAsync(
// https://github.com/iv-org/invidious/issues/3230#issuecomment-1226887639
request.Headers.Add(
"User-Agent",
"com.google.ios.youtube/19.29.1 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X)"
"com.google.ios.youtube/19.45.4 (iPhone16,2; U; CPU iOS 18_1_0 like Mac OS X; US)"
);

using var response = await Http.SendAsync(request, cancellationToken);
Expand Down

0 comments on commit 5690324

Please sign in to comment.