using System.Net; using System.Net.Mime; using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using DotBased.Monads; using Manager.YouTube.Models; using Manager.YouTube.Models.Innertube; using Manager.YouTube.Parsers; using Manager.YouTube.Util; namespace Manager.YouTube; public static class NetworkService { private const string Origin = "https://www.youtube.com"; public static async Task> GetClientStateAsync(YouTubeClient client) { var httpRequest = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri(Origin) }; httpRequest.Headers.Clear(); httpRequest.Headers.UserAgent.ParseAdd(client.UserAgent); var http = client.GetHttpClient(); if (http == null) { return ResultError.Fail("Unable to get http client!"); } var response = await http.SendAsync(httpRequest); if (!response.IsSuccessStatusCode) { var responseResult = await response.Content.ReadAsStringAsync(); return ResultError.Fail(responseResult); } var responseHtml = await response.Content.ReadAsStringAsync(); var clientStateResult = HtmlParser.GetStateJson(responseHtml); if (clientStateResult is { IsSuccess: false, Error: not null }) { return clientStateResult.Error; } ClientState? clientState; try { clientState = JsonSerializer.Deserialize(clientStateResult.Value.Item1); } catch (Exception e) { return ResultError.Error(e, "Error while parsing JSON!"); } return clientState == null ? ResultError.Fail("Unable to parse client state!") : clientState; } public static async Task> GetDatasyncIds(YouTubeClient client) { if (client.ClientState is not { LoggedIn: true } || client.CookieContainer.Count == 0) { return ResultError.Fail("Client is not logged in, requires logged in client for this endpoint (/getDatasyncIdsEndpoint)."); } var httpClient = client.GetHttpClient(); if (httpClient == null) { return ResultError.Fail("Unable to get http client!"); } var httpRequest = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"{Origin}/getDatasyncIdsEndpoint") }; httpRequest.Headers.UserAgent.ParseAdd(client.UserAgent); httpRequest.Headers.Add("Origin", Origin); var response = await httpClient.SendAsync(httpRequest); if (!response.IsSuccessStatusCode) { var responseResult = await response.Content.ReadAsStringAsync(); return ResultError.Fail(responseResult); } var responseContent = await response.Content.ReadAsStringAsync(); var datasyncIdsJson = JsonNode.Parse(responseContent.Replace(")]}'", "")); var isLoggedOut = datasyncIdsJson?["responseContext"]?["mainAppWebResponseContext"]?["loggedOut"] .Deserialize() ?? true; if (!isLoggedOut) { return datasyncIdsJson?["datasyncIds"].Deserialize() ?? []; } return ResultError.Fail("Failed to get datasyncIds!"); } public static async Task> GetCurrentAccountInfoAsync(YouTubeClient client) { if (client.ClientState is not { LoggedIn: true }) { return ResultError.Fail("Client not logged in!"); } var httpRequest = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri($"{Origin}/youtubei/v1/account/account_menu") }; httpRequest.Headers.UserAgent.ParseAdd(client.UserAgent); httpRequest.Headers.Add("Origin", Origin); if (client.SapisidCookie != null) { httpRequest.Headers.Authorization = AuthenticationUtilities.GetSapisidHashHeader(client.ClientState.WebPlayerContextConfig?.WebPlayerContext?.DatasyncId ?? "", client.SapisidCookie.Value, Origin); } var serializedContext = JsonSerializer.SerializeToNode(client.ClientState.InnerTubeContext); var contextJson = new JsonObject { { "context", serializedContext } }; httpRequest.Content = new StringContent(contextJson.ToJsonString(), Encoding.UTF8, MediaTypeNames.Application.Json); var http = client.GetHttpClient(); if (http == null) { return ResultError.Fail("Unable to get http client!"); } try { var response = await http.SendAsync(httpRequest); if (!response.IsSuccessStatusCode) { var responseResult = await response.Content.ReadAsStringAsync(); return ResultError.Fail(responseResult); } var json = await response.Content.ReadAsStringAsync(); var jsonDocument = JsonDocument.Parse(json); var activeAccountHeader = jsonDocument.RootElement .GetProperty("actions")[0] .GetProperty("openPopupAction") .GetProperty("popup") .GetProperty("multiPageMenuRenderer") .GetProperty("header") .GetProperty("activeAccountHeaderRenderer"); var matRuns = activeAccountHeader .GetProperty("manageAccountTitle") .GetProperty("runs"); var accountPhotos = activeAccountHeader .GetProperty("accountPhoto") .GetProperty("thumbnails"); var accInfo = new AccountMenuInfo(); var highestImage = accountPhotos.EnumerateArray().OrderBy(x => x.GetProperty("width").Deserialize()) .FirstOrDefault(); accInfo.ImageUrl = highestImage.GetProperty("url").Deserialize(); accInfo.ImageWidth = highestImage.GetProperty("width").Deserialize(); accInfo.ImageHeight = highestImage.GetProperty("height").Deserialize(); foreach (var run in matRuns.EnumerateArray()) { var browseEndpoint = run.GetProperty("navigationEndpoint").GetProperty("browseEndpoint"); accInfo.AccountId = browseEndpoint.GetProperty("browseId").GetString(); accInfo.AccountHandle = browseEndpoint.GetProperty("canonicalBaseUrl").GetString()?.Replace("/", ""); } return accInfo; } catch (Exception e) { return ResultError.Error(e); } } }