From ded33569bdc65f58aeb9be05a8d16c58037e5e37 Mon Sep 17 00:00:00 2001 From: UnidentifiedX <80146445+UnidentifiedX@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:00:09 +0800 Subject: [PATCH 1/3] restructured codebase to make future updates easier --- src/YTSearch.NET.TestConsole/Program.cs | 2 ++ src/YTSearch.NET/{ => Models}/SearchedYouTubeChannel.cs | 3 +-- src/YTSearch.NET/{ => Models}/SearchedYouTubeVideo.cs | 9 ++++----- .../{ => Models}/YouTubeChannelSearchResult.cs | 4 ++-- src/YTSearch.NET/{ => Models}/YouTubeSearchResult.cs | 2 +- .../{BaseYouTubeVideo.cs => Models/YouTubeVideoBase.cs} | 9 ++++----- src/YTSearch.NET/{ => Models}/YouTubeVideoQueryResult.cs | 0 .../{ => Models}/YouTubeVideoSearchResult.cs | 6 +++--- src/YTSearch.NET/QueriedYouTubeVideo.cs | 4 ++-- 9 files changed, 19 insertions(+), 20 deletions(-) rename src/YTSearch.NET/{ => Models}/SearchedYouTubeChannel.cs (94%) rename src/YTSearch.NET/{ => Models}/SearchedYouTubeVideo.cs (74%) rename src/YTSearch.NET/{ => Models}/YouTubeChannelSearchResult.cs (80%) rename src/YTSearch.NET/{ => Models}/YouTubeSearchResult.cs (94%) rename src/YTSearch.NET/{BaseYouTubeVideo.cs => Models/YouTubeVideoBase.cs} (90%) rename src/YTSearch.NET/{ => Models}/YouTubeVideoQueryResult.cs (100%) rename src/YTSearch.NET/{ => Models}/YouTubeVideoSearchResult.cs (82%) diff --git a/src/YTSearch.NET.TestConsole/Program.cs b/src/YTSearch.NET.TestConsole/Program.cs index ad141f0..42cc8e6 100644 --- a/src/YTSearch.NET.TestConsole/Program.cs +++ b/src/YTSearch.NET.TestConsole/Program.cs @@ -14,6 +14,8 @@ static async Task Main(string[] args) //var a = await client.SearchYouTubeChannelAsync("rick astley"); var a = await client.GetVideoMetadataAsync("qUeud6DvOWI"); + //var a = (await client.SearchYoutubeVideoAsync("never gonna give you up")).Results.First().Url; + //var a = (await client.SearchYoutubeVideoAsync("beautiful girls")); Debugger.Break(); diff --git a/src/YTSearch.NET/SearchedYouTubeChannel.cs b/src/YTSearch.NET/Models/SearchedYouTubeChannel.cs similarity index 94% rename from src/YTSearch.NET/SearchedYouTubeChannel.cs rename to src/YTSearch.NET/Models/SearchedYouTubeChannel.cs index 8915739..3ab56fc 100644 --- a/src/YTSearch.NET/SearchedYouTubeChannel.cs +++ b/src/YTSearch.NET/Models/SearchedYouTubeChannel.cs @@ -4,9 +4,8 @@ using System.Text; using System.Text.Json.Nodes; using System.Threading.Tasks; -using YTSearch.NET.Models; -namespace YTSearch.NET +namespace YTSearch.NET.Models { public class SearchedYouTubeChannel { diff --git a/src/YTSearch.NET/SearchedYouTubeVideo.cs b/src/YTSearch.NET/Models/SearchedYouTubeVideo.cs similarity index 74% rename from src/YTSearch.NET/SearchedYouTubeVideo.cs rename to src/YTSearch.NET/Models/SearchedYouTubeVideo.cs index 45f7e67..24379c5 100644 --- a/src/YTSearch.NET/SearchedYouTubeVideo.cs +++ b/src/YTSearch.NET/Models/SearchedYouTubeVideo.cs @@ -1,14 +1,13 @@ using System; -using YTSearch.NET.Models; -namespace YTSearch.NET +namespace YTSearch.NET.Models { /// - /// Class SearchedYoutubeVideo inherits from and shows extra video information extracted from video searchess + /// Class SearchedYoutubeVideo inherits from and shows extra video information extracted from video searchess /// - public class SearchedYouTubeVideo : BaseYouTubeVideo + public class SearchedYouTubeVideo : YouTubeVideoBase { - public SearchedYouTubeVideo(string? title, string? videoId, Thumbnail[] thumbnails, TimeSpan length, string? author, int? views, string? published) + public SearchedYouTubeVideo(string? title, string? videoId, Thumbnail[] thumbnails, TimeSpan length, string? author, int? views, string? published) : base(title, videoId, thumbnails, length, author, views) { Published = published; diff --git a/src/YTSearch.NET/YouTubeChannelSearchResult.cs b/src/YTSearch.NET/Models/YouTubeChannelSearchResult.cs similarity index 80% rename from src/YTSearch.NET/YouTubeChannelSearchResult.cs rename to src/YTSearch.NET/Models/YouTubeChannelSearchResult.cs index cc04723..7180abd 100644 --- a/src/YTSearch.NET/YouTubeChannelSearchResult.cs +++ b/src/YTSearch.NET/Models/YouTubeChannelSearchResult.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -namespace YTSearch.NET +namespace YTSearch.NET.Models { public class YouTubeChannelSearchResult : YouTubeSearchResult { - public YouTubeChannelSearchResult(string query, string url, ICollection results) + public YouTubeChannelSearchResult(string query, string url, ICollection results) : base(query, url) { Results = results; diff --git a/src/YTSearch.NET/YouTubeSearchResult.cs b/src/YTSearch.NET/Models/YouTubeSearchResult.cs similarity index 94% rename from src/YTSearch.NET/YouTubeSearchResult.cs rename to src/YTSearch.NET/Models/YouTubeSearchResult.cs index 37f3e4c..9251d72 100644 --- a/src/YTSearch.NET/YouTubeSearchResult.cs +++ b/src/YTSearch.NET/Models/YouTubeSearchResult.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading.Tasks; -namespace YTSearch.NET +namespace YTSearch.NET.Models { public abstract class YouTubeSearchResult { diff --git a/src/YTSearch.NET/BaseYouTubeVideo.cs b/src/YTSearch.NET/Models/YouTubeVideoBase.cs similarity index 90% rename from src/YTSearch.NET/BaseYouTubeVideo.cs rename to src/YTSearch.NET/Models/YouTubeVideoBase.cs index 5fbb00c..e4e8968 100644 --- a/src/YTSearch.NET/BaseYouTubeVideo.cs +++ b/src/YTSearch.NET/Models/YouTubeVideoBase.cs @@ -1,15 +1,14 @@ using System; -using YTSearch.NET.Models; -namespace YTSearch.NET +namespace YTSearch.NET.Models { /// /// Abstract class BaseYouTubeVideo shows basic extracted information for a YouTube video /// - - public abstract class BaseYouTubeVideo + + public abstract class YouTubeVideoBase { - public BaseYouTubeVideo(string? title, string? videoId, Thumbnail[] thumbnails, TimeSpan length, string? author, int? views) + public YouTubeVideoBase(string? title, string? videoId, Thumbnail[] thumbnails, TimeSpan length, string? author, int? views) { Title = title; VideoId = videoId; diff --git a/src/YTSearch.NET/YouTubeVideoQueryResult.cs b/src/YTSearch.NET/Models/YouTubeVideoQueryResult.cs similarity index 100% rename from src/YTSearch.NET/YouTubeVideoQueryResult.cs rename to src/YTSearch.NET/Models/YouTubeVideoQueryResult.cs diff --git a/src/YTSearch.NET/YouTubeVideoSearchResult.cs b/src/YTSearch.NET/Models/YouTubeVideoSearchResult.cs similarity index 82% rename from src/YTSearch.NET/YouTubeVideoSearchResult.cs rename to src/YTSearch.NET/Models/YouTubeVideoSearchResult.cs index f109b5c..63d83a7 100644 --- a/src/YTSearch.NET/YouTubeVideoSearchResult.cs +++ b/src/YTSearch.NET/Models/YouTubeVideoSearchResult.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace YTSearch.NET +namespace YTSearch.NET.Models { public class YouTubeVideoSearchResult : YouTubeSearchResult { @@ -8,8 +8,8 @@ public class YouTubeVideoSearchResult : YouTubeSearchResult /// /// Search result class /// - public YouTubeVideoSearchResult(string query, string url, ICollection results) - :base(query, url) + public YouTubeVideoSearchResult(string query, string url, ICollection results) + : base(query, url) { Results = results; } diff --git a/src/YTSearch.NET/QueriedYouTubeVideo.cs b/src/YTSearch.NET/QueriedYouTubeVideo.cs index a395219..41e2b2f 100644 --- a/src/YTSearch.NET/QueriedYouTubeVideo.cs +++ b/src/YTSearch.NET/QueriedYouTubeVideo.cs @@ -4,9 +4,9 @@ namespace YTSearch.NET { /// - /// Class QueriedYouTubeVideo inherits from and shows extra video information extracted from a YouTube video + /// Class QueriedYouTubeVideo inherits from and shows extra video information extracted from a YouTube video /// - public class QueriedYouTubeVideo : BaseYouTubeVideo + public class QueriedYouTubeVideo : YouTubeVideoBase { public QueriedYouTubeVideo(string? title, string? videoId, Thumbnail[] thumbnails, TimeSpan length, string? author, int? views, string[]? keywords, string? description, bool? isCrawlable, bool? isRatingEnabled, bool? isPrivate, bool? isLiveContent, DateTime publishedDate, DateTime uploadedDate, bool? isFamilyFriendly, string[]? availableCountries, bool? isUnlisted, string? category) : base(title, videoId, thumbnails, length, author, views) From f6a87bb0f2d8a2c0982d83a014121b1a32da3036 Mon Sep 17 00:00:00 2001 From: UnidentifiedX <80146445+UnidentifiedX@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:25:46 +0800 Subject: [PATCH 2/3] Moved Utils to SearchUtils class --- src/YTSearch.NET/Utils/SearchUtils.cs | 85 ++++++++++++++++++++++++ src/YTSearch.NET/YouTubeSearchClient.cs | 88 +++---------------------- 2 files changed, 95 insertions(+), 78 deletions(-) create mode 100644 src/YTSearch.NET/Utils/SearchUtils.cs diff --git a/src/YTSearch.NET/Utils/SearchUtils.cs b/src/YTSearch.NET/Utils/SearchUtils.cs new file mode 100644 index 0000000..44df577 --- /dev/null +++ b/src/YTSearch.NET/Utils/SearchUtils.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.Json.Nodes; +using YTSearch.NET.Models; + +namespace YTSearch.NET.Utils +{ + internal static class SearchUtils + { + internal static int? KMBToInt(string? kmb) + { + if (kmb == null) return null; + + try + { + if (kmb.ToLower().Contains('k')) + { + return (int)(float.Parse(kmb.ToLower().Replace("k", "")) * 1000); + } + else if (kmb.ToLower().Contains('m')) + { + return (int)(float.Parse(kmb.ToLower().Replace("m", "")) * 1000000); + } + else if (kmb.ToLower().Contains('b')) + { + return (int)(float.Parse(kmb.ToLower().Replace("b", "")) * 1000000000); + } + else + { + return int.Parse(kmb); + } + } + catch + { + return null; + } + } + + internal static TimeSpan ParseVideoLength(string? timespan) + { + var output = TimeSpan.Zero; + if (timespan != null) + { + try + { + switch (timespan.Split(':').Length) + { + case 1: + output = TimeSpan.ParseExact(timespan, "%s", CultureInfo.InvariantCulture); + break; + case 2: + output = TimeSpan.ParseExact(timespan, @"m\:ss", CultureInfo.InvariantCulture); + break; + default: + output = TimeSpan.ParseExact(timespan, "g", CultureInfo.InvariantCulture); + break; + } + } + catch + { + output = TimeSpan.Zero; + } + } + + return output; + } + + internal static Thumbnail[] ParseThumbnails(JsonNode? jsonNode) + { + var thumbnails = new List(); + jsonNode?.AsArray().ToList().ForEach(thumbnail => + { + var width = (int?)thumbnail?["width"]; + var height = (int?)thumbnail?["height"]; + var url = (string?)thumbnail?["url"]; + thumbnails.Add(new Thumbnail(width, height, url)); + }); + + return thumbnails.ToArray(); + } + } +} diff --git a/src/YTSearch.NET/YouTubeSearchClient.cs b/src/YTSearch.NET/YouTubeSearchClient.cs index 2825551..89d80ad 100644 --- a/src/YTSearch.NET/YouTubeSearchClient.cs +++ b/src/YTSearch.NET/YouTubeSearchClient.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using System.Web; using YTSearch.NET.Models; +using YTSearch.NET.Utils; namespace YTSearch.NET { @@ -47,8 +48,8 @@ public async Task SearchYoutubeVideoAsync(string query var title = (string?)video?["title"]?["runs"]?[0]?["text"]; var videoId = (string?)video?["videoId"]; - var thumbnails = ParseThumbnails(video?["thumbnail"]?["thumbnails"]); - var length = ParseVideoLength((string?)video?["lengthText"]?["simpleText"]); + var thumbnails = SearchUtils.ParseThumbnails(video?["thumbnail"]?["thumbnails"]); + var length = SearchUtils.ParseVideoLength((string?)video?["lengthText"]?["simpleText"]); var author = (string?)video?["ownerText"]?["runs"]?[0]?["text"]; int? views = int.TryParse(((string?)video?["viewCountText"]?["simpleText"])?.Replace(",", "")?.Replace("views", ""), out int parsed) ? parsed : (int?)null; // (int?) cast to target netstandard2.1 var published = (string?)video?["publishedTimeText"]?["simpleText"]; @@ -83,7 +84,7 @@ public async Task SearchYouTubeChannelAsync(string q var channelId = (string?)channel?["channelId"]; var name = (string?)channel?["title"]?["simpleText"]; - var thumbnails = ParseThumbnails(channel?["thumbnail"]?["thumbnails"]); + var thumbnails = SearchUtils.ParseThumbnails(channel?["thumbnail"]?["thumbnails"]); var descriptionSnippet = channel?["descriptionSnippet"]?["runs"]?[0]?["text"]; // YouTube does this weird thing where they send subscriber count in the view/video count text, so we have to check for them @@ -92,16 +93,16 @@ public async Task SearchYouTubeChannelAsync(string q if ((string?)channel?["videoCountText"]?["simpleText"] != null && ((string?)channel?["videoCountText"]?["simpleText"]).Contains("subscriber")) { - subscriberCount = KMBToInt(((string?)channel?["videoCountText"]?["simpleText"])?.Split(' ')[0]); + subscriberCount = SearchUtils.KMBToInt(((string?)channel?["videoCountText"]?["simpleText"])?.Split(' ')[0]); } else { - subscriberCount = KMBToInt(((string?)channel?["subscriberCountText"]?["simpleText"])?.Split(' ')[0]); + subscriberCount = SearchUtils.KMBToInt(((string?)channel?["subscriberCountText"]?["simpleText"])?.Split(' ')[0]); } if ((string?)channel?["videoCountText"]?["runs"]?[0]?["text"] != null && ((string?)channel?["videoCountText"]?["runs"]?[0]?["text"]).Contains("video")) { - videoCount = KMBToInt(((string?)channel?["videoCountText"]?["runs"]?[0]?["text"])?.Split(' ')[0]); + videoCount = SearchUtils.KMBToInt(((string?)channel?["videoCountText"]?["runs"]?[0]?["text"])?.Split(' ')[0]); } searchResults.Add(new SearchedYouTubeChannel(channelId, name, thumbnails, descriptionSnippet, videoCount, subscriberCount)); @@ -138,7 +139,7 @@ public async Task GetVideoMetadataAsync(Uri uri) var title = (string?)videoDetail?["title"]; var videoId = (string?)videoDetail?["videoId"]; - var thumbnails = ParseThumbnails(videoDetail?["thumbnail"]?["thumbnails"]); + var thumbnails = SearchUtils.ParseThumbnails(videoDetail?["thumbnail"]?["thumbnails"]); var length = TimeSpan.FromSeconds(int.Parse((string?)videoDetail?["lengthSeconds"])); var author = (string?)videoDetail?["author"]; var views = int.Parse((string?)videoDetail?["viewCount"]); @@ -179,77 +180,8 @@ public async Task GetVideoMetadataAsync(Uri uri) } #endregion + #region Channel Metadata - private static Thumbnail[] ParseThumbnails(JsonNode? jsonNode) - { - var thumbnails = new List(); - jsonNode?.AsArray().ToList().ForEach(thumbnail => - { - var width = (int?)thumbnail?["width"]; - var height = (int?)thumbnail?["height"]; - var url = (string?)thumbnail?["url"]; - thumbnails.Add(new Thumbnail(width, height, url)); - }); - - return thumbnails.ToArray(); - } - - private static TimeSpan ParseVideoLength(string? timespan) - { - var output = TimeSpan.Zero; - if (timespan != null) - { - try - { - switch (timespan.Split(':').Length) - { - case 1: - output = TimeSpan.ParseExact(timespan, "%s", CultureInfo.InvariantCulture); - break; - case 2: - output = TimeSpan.ParseExact(timespan, @"m\:ss", CultureInfo.InvariantCulture); - break; - default: - output = TimeSpan.ParseExact(timespan, "g", CultureInfo.InvariantCulture); - break; - } - } - catch - { - output = TimeSpan.Zero; - } - } - - return output; - } - - private static int? KMBToInt(string? kmb) - { - if(kmb == null) return null; - - try - { - if (kmb.ToLower().Contains('k')) - { - return (int)(float.Parse(kmb.ToLower().Replace("k", "")) * 1000); - } - else if (kmb.ToLower().Contains('m')) - { - return (int)(float.Parse(kmb.ToLower().Replace("m", "")) * 1000000); - } - else if (kmb.ToLower().Contains('b')) - { - return (int)(float.Parse(kmb.ToLower().Replace("b", "")) * 1000000000); - } - else - { - return int.Parse(kmb); - } - } - catch - { - return null; - } - } + #endregion } } \ No newline at end of file From abc028c4fa7eafe0c9cfe701d4d8aa501ff5a4ba Mon Sep 17 00:00:00 2001 From: UnidentifiedX Date: Fri, 23 Aug 2024 11:45:28 +0800 Subject: [PATCH 3/3] updated tests --- src/YTSearch.NET.Tests/YouTubeSearchTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YTSearch.NET.Tests/YouTubeSearchTests.cs b/src/YTSearch.NET.Tests/YouTubeSearchTests.cs index 4062fc9..56cd359 100644 --- a/src/YTSearch.NET.Tests/YouTubeSearchTests.cs +++ b/src/YTSearch.NET.Tests/YouTubeSearchTests.cs @@ -32,7 +32,7 @@ public async Task SearchYoutube_TitleSearchWithoutFlags_CorrectVideoDetails() Assert.That(a.Url, Is.EqualTo("https://www.youtube.com/watch?v=dQw4w9WgXcQ")); Assert.That(a.Length, Is.EqualTo(TimeSpan.FromSeconds(213))); Assert.That(a.Author, Is.EqualTo("Rick Astley")); - Assert.That(a.Published, Is.EqualTo("13 years ago")); + Assert.That(a.Published, Is.EqualTo("14 years ago")); }); } }