Skip to content

Commit 84e29bb

Browse files
authored
Extract visitor data from YouTube API (#870)
1 parent 0cad7e6 commit 84e29bb

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

YoutubeExplode/Bridge/VisitorData.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using System.Linq;
3-
using System.Text;
3+
using System.Net.Http;
4+
using System.Net.Http.Headers;
5+
using System.Text.Json;
6+
using System.Threading.Tasks;
47
using YoutubeExplode.Utils;
58
using YoutubeExplode.Utils.Extensions;
69

@@ -11,6 +14,7 @@ internal static class VisitorData
1114
private static readonly Random Random = new();
1215
private static readonly char[] SessionIdAllowedChars =
1316
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".ToCharArray();
17+
private static string _visitorData = string.Empty;
1418

1519
public static string Generate() =>
1620
new ProtoBuilder()
@@ -36,4 +40,53 @@ public static string Generate() =>
3640
.ToBytes()
3741
)
3842
.ToUrlEncodedBase64();
43+
44+
public static async Task<string> ExtractFromYoutube(HttpClient http)
45+
{
46+
//avoid fetching visitor data for each request (?) could slow down the app
47+
if (!string.IsNullOrEmpty(_visitorData))
48+
return _visitorData;
49+
50+
//use the same iOS user agent (?) idk if it's necessary
51+
http.DefaultRequestHeaders.UserAgent.ParseAdd(
52+
"com.google.ios.youtube/19.45.4 (iPhone16,2; U; CPU iOS 18_1_0 like Mac OS X; US)"
53+
);
54+
55+
//request JSON format
56+
http.DefaultRequestHeaders.Accept.Add(
57+
new MediaTypeWithQualityHeaderValue("application/json")
58+
);
59+
60+
var url = "https://www.youtube.com/sw.js_data";
61+
HttpResponseMessage response = await http.GetAsync(url);
62+
response.EnsureSuccessStatusCode();
63+
string jsonString = await response.Content.ReadAsStringAsync();
64+
65+
//Remove the prefix ")]}'"
66+
if (jsonString.StartsWith(")]}'"))
67+
jsonString = jsonString.Substring(4);
68+
69+
using (JsonDocument doc = JsonDocument.Parse(jsonString))
70+
{
71+
JsonElement root = doc.RootElement;
72+
73+
//jsonArray[0][2][0][0][13]
74+
var value = root[0]
75+
.EnumerateArray()
76+
.ElementAt(2)
77+
.EnumerateArray()
78+
.ElementAt(0)
79+
.EnumerateArray()
80+
.ElementAt(0)
81+
.EnumerateArray()
82+
.ElementAt(13)
83+
.GetString();
84+
85+
if (value == null)
86+
throw new Exception("Failed to fetch visitor data");
87+
88+
_visitorData = value;
89+
}
90+
return _visitorData;
91+
}
3992
}

YoutubeExplode/Videos/VideoController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public async ValueTask<PlayerResponse> GetPlayerResponseAsync(
7676
"platform": "MOBILE",
7777
"osName": "IOS",
7878
"osVersion": "18.1.0.22B83",
79-
"visitorData": {{Json.Serialize(VisitorData.Generate())}},
79+
"visitorData": {{Json.Serialize(await VisitorData.ExtractFromYoutube(Http))}},
8080
"hl": "en",
8181
"gl": "US",
8282
"utcOffsetMinutes": 0

0 commit comments

Comments
 (0)