Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Commit

Permalink
Implement continuation for /next (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuylar authored Feb 1, 2024
1 parent 2110223 commit 1309650
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
14 changes: 14 additions & 0 deletions InnerTube.Tests/PlayerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ public async Task GetVideoNext(string videoId)
Assert.Pass(sb.ToString());
}

[TestCase("CBQSKRILMlFPNDBIalJIMnfAAQDIAQDgAQOiAg0o____________AUAA-AIAGAAqmAsyczZMNnd5ckNBcW9DQW9EOGo0QUNnM0NQZ29JcFBXZDF1UzM1WmwwQ2czQ1Bnb0l0SXppd3YzZno2TmpDZzNDUGdvSTY1RHprY1hnOXR3RkNnN0NQZ3NJck1HcHRLaW04ZnVpQVFvT3dqNExDUGJSZzYtUHdfX2V4UUVLRHNJLUN3aXI4WnpSd3FEbjZMQUJDZzdDUGdzSTlvSDBpc245cDVYVkFRb093ajRMQ1BUMTA1anR3OEtDX3dFS0RjSS1DZ2pOM1l5aThQVFB1Z1VLRGNJLUNnakg5OTdSdTRqMjdoQUtEY0ktQ2dpOS1jR0c3N1NONGlBS0RzSS1Dd2o3cHA3bnVON3N2UFFCQ2c3Q1Bnc0luSnp3aktmeTVfamFBUW9Od2o0S0NNZU4yYnV4clpydmJBb053ajRLQ0lPcTA2LTM3c2VpQXdvTXdqNEpDTWJac2ZqeDlfNGxDZzNDUGdvSXZ1S0V1OEN4LS1rS0NnM0NQZ29JbkltaXk5ZTU5dkV6Q2c3Q1Bnc0kwSUwyd3B5dnNPV3FBUW9Od2o0S0NKZXVpSlQ4NHFXd0FRb053ajRLQ09MYzZjLV9ucC05U1FvT3dqNExDSXlRX19qWnJMVFk4QUVLQV9JLUFBb053ajRLQ1A3U3NJMnZzWUdZSEFvRDhqNEFDaF9TUGh3S0dsSkVSVTFKUVhSYU4zZFRibVZzTm1waFQyNDBjVjlwUjNWbkNnUHlQZ0FLRHNJLUN3akY1cHZXMGZ1bms4NEJDZ1B5UGdBS0RjSS1DZ2prc2RLbnFhM0FfbE1LQV9JLUFBb053ajRLQ0lQZTRlLUkwcUxpT1FvRDhqNEFDZzdDUGdzSXlkVC1nY3pPai1MS0FRb0Q4ajRBQ2czQ1Bnb0lxcC15cWZyQXpyaHRDZ1B5UGdBS0RzSS1Dd2lya2MzQ204LU56bzRCQ2dQeVBnQUtEc0ktQ3dpYzFLcjZ1TG1ELUw0QkNnUHlQZ0FLRHNJLUN3alA5ZUMzcVpxLXBPb0JDZ1B5UGdBS0RjSS1DZ2pzNmNHMzlPYXY5bmtLQV9JLUFBb093ajRMQ05qTHJ2REZ3WS1icUFFS0FfSS1BQW9Od2o0S0NLLTJ5YVdobGQzNVlBb0Q4ajRBQ2czQ1Bnb0lzcDNGbE5yaTJOUmpDZ1B5UGdBS0RzSS1Dd2lsbjlYSXBhT3JrdGNCQ2dQeVBnQUtEc0ktQ3dqcXRLdWExNm1ua3ZrQkNnUHlQZ0FLRGNJLUNnaXI3OWUzejVmUzYxUUtBX0ktQUFvT3dqNExDSzIxanRUNXFiLWctZ0VLQV9JLUFBb0owajRHQ2dSU1JFMU5DZ1B5UGdBS0RjSS1DZ2lxOThqNW1hM1dxblVTRlFBWEdSc2RIeUVqSlNjcEt5MHZNVE0xTnprN1BSb0VDQUFRQVJvRUNBQVFBaG9FQ0FBUUF4b0VDQUFRQkJvRUNBQVFCUm9FQ0FBUUJob0VDQUFRQnhvRUNBQVFDQm9FQ0FBUUNSb0VDQUFRQ2hvRUNBQVFDeG9FQ0FBUURCb0VDQUFRRFJvRUNBQVFEaG9FQ0FBUUR4b0VDQUFRRUJvRUNBQVFFUm9FQ0FBUUVob0VDQUFRRXhvRUNBQVFGQm9FQ0FBUUZSb0VDQUFRRmhvRUNCY1FHQm9FQ0JrUUdob0VDQnNRSEJvRUNCMFFIaG9FQ0I4UUlCb0VDQ0VRSWhvRUNDTVFKQm9FQ0NVUUpob0VDQ2NRS0JvRUNDa1FLaG9FQ0NzUUxCb0VDQzBRTGhvRUNDOFFNQm9FQ0RFUU1ob0VDRE1RTkJvRUNEVVFOaG9FQ0RjUU9Cb0VDRGtRT2hvRUNEc1FQQm9FQ0QwUVBpb1ZBQmNaR3gwZklTTWxKeWtyTFM4eE16VTNPVHM5ag93YXRjaC1uZXh0LWZlZWQ%3D")]
public async Task ContinueVideoNext(string continuation)
{
InnerTubeContinuationResponse response = await _innerTube.ContinueVideoAsync(continuation);
StringBuilder sb = new();

foreach (IRenderer renderer in response.Contents)
sb.AppendLine("->\t" + string.Join("\n\t", (renderer.ToString() ?? "UNKNOWN RENDERER " + renderer.Type).Split("\n")));

sb.AppendLine($"Continuation: {response.Continuation?.Substring(0, 20)}");

Assert.Pass(sb.ToString());
}

[TestCase("3BR7-AzE2dQ", "OLAK5uy_l6pEkEJgy577R-aDlJ3Gkp5rmlgIOu8bc", null, null)]
[TestCase("o0tky2O8NlY", "OLAK5uy_l6pEkEJgy577R-aDlJ3Gkp5rmlgIOu8bc", null, null)]
[TestCase("NZwS7Cja6oE", "PLv3TTBr1W_9tppikBxAE_G6qjWdBljBHJ", null, null)]
Expand Down
17 changes: 17 additions & 0 deletions InnerTube/InnerTube.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,23 @@ public async Task<InnerTubeNextResponse> GetVideoAsync(string videoId, string? p
return new InnerTubeNextResponse(nextResponse);
}

/// <summary>
/// Continues the video recommendations from the last continuation token
/// </summary>
/// <param name="continuation">Continuation token received from GetVideoAsync</param>
/// <param name="language">Language of the content</param>
/// <param name="region">Region of the content</param>
/// <returns>List of recommended content for the video that belongs to the specified key</returns>
public async Task<InnerTubeContinuationResponse> ContinueVideoAsync(string continuation,
string language = "en", string region = "US")
{
InnerTubeRequest postData = new InnerTubeRequest()
.AddValue("continuation", continuation);

JObject nextResponse = await MakeRequest(RequestClient.WEB, "next", postData, language, region);
return InnerTubeContinuationResponse.GetFromNext(nextResponse);
}

/// <summary>
/// Gets the comments of a video from a comment continuation token that can be received from GetVideoAsync
/// </summary>
Expand Down
8 changes: 8 additions & 0 deletions InnerTube/Models/InnerTubeContinuationResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,12 @@ public static InnerTubeContinuationResponse GetFromBrowse(JObject browseResponse
return new InnerTubeContinuationResponse(contents.Where(x => x is not ContinuationItemRenderer),
((ContinuationItemRenderer?)contents.FirstOrDefault(x => x is ContinuationItemRenderer))?.Token);
}

public static InnerTubeContinuationResponse GetFromNext(JObject browseResponse)
{
IEnumerable<IRenderer> contents = RendererManager.ParseRenderers(browseResponse.GetFromJsonPath<JArray>(
"onResponseReceivedEndpoints[0].appendContinuationItemsAction.continuationItems")!).ToArray();
return new InnerTubeContinuationResponse(contents.Where(x => x is not ContinuationItemRenderer),
((ContinuationItemRenderer?)contents.FirstOrDefault(x => x is ContinuationItemRenderer))?.Token);
}
}

0 comments on commit 1309650

Please sign in to comment.