Skip to content

Commit

Permalink
Changes:
Browse files Browse the repository at this point in the history
- Introduced GetRepositoryInfoAsync() to retrieve informations about a specific GitHub repository
- Added a repository-class for the GetRepositoryInfoAsync() method
- Moved models in a dedicated "Models" folder
- Changed data types for TotalStars and TotalForks from string to integer
  • Loading branch information
liebki committed Jun 19, 2023
1 parent 9c79e40 commit a0e72df
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 67 deletions.
3 changes: 2 additions & 1 deletion GithubNet/GithubNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>GithubNet</Title>
<Version>0.1</Version>
<Version>0.2</Version>
<Authors>liebki</Authors>
<Description>This library allows you to retrieve trending GitHub repositories and their information.</Description>
<Copyright>liebki</Copyright>
Expand All @@ -18,6 +18,7 @@
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageIcon>icon.png</PackageIcon>
<PackageId>GithubDataNet</PackageId>
<PackageReleaseNotes>The update includes a new GetRepositoryInfoAsync() method for retrieving detailed information about GitHub repositories, a 'Repository' class to support it, and improved data types (TotalStars and TotalForks changed to integers).</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand Down
16 changes: 15 additions & 1 deletion GithubNet/GithubNetClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace GithubNet
using GithubNet.Models;

namespace GithubNet
{
public class GithubNetClient
{
Expand All @@ -14,6 +16,18 @@ public async Task<List<TrendItem>> GetTrendItemsAsync(bool loadTrendItemDetails
}
}

public async Task<Repository> GetRepositoryInfoAsync(string repositoryLink)
{
if (!string.IsNullOrEmpty(repositoryLink) && repositoryLink.StartsWith("https://github.com/", StringComparison.InvariantCultureIgnoreCase))
{
return await GithubNetManager.GetRepositoryInfo(repositoryLink);
}
else
{
throw new ArgumentException("The parameter customquery, can't be whitespace, null or empty also it has to contain some kind of https://github.com/trending-url string!");
}
}

public async Task<TrendItem> GetTrendItemDetailsAsync(TrendItem entryItem)
{
if (entryItem != null && !string.IsNullOrEmpty(entryItem.RespositoryLink) && !string.IsNullOrWhiteSpace(entryItem.RespositoryLink))
Expand Down
106 changes: 98 additions & 8 deletions GithubNet/GithubNetManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using HtmlAgilityPack;
using System.Net;
using System.Net;
using System.Text;
using HtmlAgilityPack;
using GithubNet.Models;

namespace GithubNet
{
Expand Down Expand Up @@ -32,7 +33,7 @@ internal static async Task<List<TrendItem>> GetAllTrendEntries(bool loadTrendIte
}
string UsernameFiltered = FilterLineBreaks(Username.InnerText.Replace(" /", string.Empty));

string RepositoryLinkFiltered = $"https://github.com{RepositoryLink.Attributes["href"].Value}";
string RepositoryLinkFiltered = $"https://github.com{RepositoryLink.GetAttributeValue("href", string.Empty)}";
string[] RepositoryNameParse = RepositoryLinkFiltered.Split('/');

string RepositoryName = "An error occured";
Expand All @@ -42,8 +43,11 @@ internal static async Task<List<TrendItem>> GetAllTrendEntries(bool loadTrendIte
RepositoryName = RepositoryNameParse[4];
}

string TotalStarsFiltered = FilterLineBreaks(TotalForksAndStars[0].InnerText);
string TotalForksFiltered = FilterLineBreaks(TotalForksAndStars[1].InnerText);
string TotalStars = FilterLineBreaks(TotalForksAndStars[0].InnerText);
int.TryParse(TotalStars.Replace(",", string.Empty), out int TotalStarsFiltered);

string TotalForks = FilterLineBreaks(TotalForksAndStars[1].InnerText);
int.TryParse(TotalForks.Replace(",", string.Empty), out int TotalForksFiltered);

string ProgrammingLanguage = "None";
if (productElement.QuerySelectorAll("article.Box-row > div > span > span") != null)
Expand All @@ -57,12 +61,12 @@ internal static async Task<List<TrendItem>> GetAllTrendEntries(bool loadTrendIte

if (loadTrendItemDetails)
{
TrendItem trendItem = new(UsernameFiltered, RepositoryLinkFiltered, RepositoryName, DescriptionFiltered, TotalStarsFiltered, TotalForksFiltered, ProgrammingLanguage);
TrendItem trendItem = new(ProgrammingLanguage, false, false, string.Empty, string.Empty, UsernameFiltered, RepositoryLinkFiltered, RepositoryName, DescriptionFiltered, TotalStarsFiltered, TotalForksFiltered, false, string.Empty, false, Array.Empty<string>());
TrendingRepositoriesList.Add(await GetTrendDetails(trendItem));
}
else
{
TrendingRepositoriesList.Add(new(UsernameFiltered, RepositoryLinkFiltered, RepositoryName, DescriptionFiltered, TotalStarsFiltered, TotalForksFiltered, ProgrammingLanguage));
TrendingRepositoriesList.Add(new(ProgrammingLanguage, false, false, string.Empty, string.Empty, UsernameFiltered, RepositoryLinkFiltered, RepositoryName, DescriptionFiltered, TotalStarsFiltered, TotalForksFiltered, false, string.Empty, false, Array.Empty<string>()));
}
}
catch (Exception)
Expand All @@ -74,6 +78,92 @@ internal static async Task<List<TrendItem>> GetAllTrendEntries(bool loadTrendIte
return TrendingRepositoriesList;
}

private static async Task<ItemBase> FillBaseData(HtmlNode node, string repositoryUrl)
{
HtmlNode Username = node.SelectSingleNode("/html/body/div[1]/div[4]/div/main/div/div[1]/div[1]/div/span[1]/a");
HtmlNode RepositoryName = node.SelectSingleNode("/html/body/div[1]/div[4]/div/main/div/div[1]/div[1]/div/strong/a");

HtmlNode Description = node.SelectSingleNode("/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div[2]/div[2]/div/div[1]/div/p");
HtmlNode TotalForks = node.SelectSingleNode("//*[@id=\"repo-network-counter\"]");

HtmlNode TotalStars = node.SelectSingleNode("//*[@id=\"repo-stars-counter-star\"]");
HtmlNode ProjectUrl = node.SelectSingleNode("/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div[2]/div[2]/div/div[1]/div/div[1]/span/a");

HtmlNode Topics = node.SelectSingleNode("/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div[2]/div[2]/div/div[1]/div/div[2]/div");

string DescriptionFiltered = FilterLineBreaks(Description.InnerText);
if (!string.IsNullOrWhiteSpace(DescriptionFiltered))
{
DescriptionFiltered = WebUtility.HtmlDecode(DescriptionFiltered);
}

List<string> TopicsFiltered = new();
bool HasTopics = false;

if (Topics != null)
{
HasTopics = true;
IList<HtmlNode> TopicsValues = Topics.QuerySelectorAll("a.topic-tag");

foreach (HtmlNode t in TopicsValues)
{
TopicsFiltered.Add(FilterLineBreaks(t.InnerHtml));
}
}

string ProjectUrlFiltered = string.Empty;
bool HasProjectUrl = false;

if (ProjectUrl != null)
{
HasProjectUrl = true;
ProjectUrlFiltered = ProjectUrl.GetAttributeValue("href", string.Empty);
}

string ForksValue = TotalForks.GetAttributeValue("title", string.Empty);
int.TryParse(ForksValue.Replace(",", string.Empty), out int ForksFiltered);

string StarsValue = TotalStars.GetAttributeValue("title", string.Empty);
int.TryParse(StarsValue.Replace(",", string.Empty), out int StarsFiltered);

string UsernameFiltered = FilterLineBreaks(Username.InnerText.Replace(" /", string.Empty));
string RepositoryNameFiltered = FilterLineBreaks(RepositoryName.InnerText.Replace(" /", string.Empty));

return new(UsernameFiltered, repositoryUrl, RepositoryNameFiltered, DescriptionFiltered, StarsFiltered, ForksFiltered, HasProjectUrl, ProjectUrlFiltered, HasTopics, TopicsFiltered.ToArray());
}

internal static async Task<Repository> GetRepositoryInfo(string repositoryLink)
{
HtmlWeb CommitUrl = new();
HtmlDocument TrendingRep = CommitUrl.Load(repositoryLink);

ItemBase baseData = await FillBaseData(TrendingRep.DocumentNode, repositoryLink);
HtmlNode OpenIssuesNumber = TrendingRep.DocumentNode.SelectSingleNode("//*[@id=\"issues-repo-tab-count\"]");

HtmlNode OpenPullRequestsNumber = TrendingRep.DocumentNode.SelectSingleNode("//*[@id=\"pull-requests-repo-tab-count\"]");
HtmlNode TotalCommitsNumber = TrendingRep.DocumentNode.SelectSingleNode("/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div[2]/div[1]/div[2]/div[1]/div/div[4]/ul/li/a/span/strong");

HtmlNode TotalContributorsNumber = TrendingRep.DocumentNode.SelectSingleNode("/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div[2]/div[2]/div/div[5]/div/h2/a/span");

string OpenIssuesNumberFiltered = FilterLineBreaks(OpenIssuesNumber.InnerHtml);
int.TryParse(OpenIssuesNumberFiltered.Replace(",", string.Empty), out int OpenIssuesNumberValue);

string OpenPullRequestsNumberFiltered = FilterLineBreaks(OpenPullRequestsNumber.InnerHtml);
int.TryParse(OpenPullRequestsNumberFiltered.Replace(",", string.Empty), out int OpenPullRequestsNumberValue);

string TotalCommitsNumberFiltered = FilterLineBreaks(TotalCommitsNumber.InnerText);
int.TryParse(TotalCommitsNumberFiltered.Replace(",", string.Empty), out int TotalCommitsNumberValue);

int TotalContributorsNumberValue = 0;
if (TotalContributorsNumber != null)
{
string TotalContributorsNumberFiltered = FilterLineBreaks(TotalContributorsNumber.InnerHtml);
int.TryParse(TotalContributorsNumberFiltered.Replace(",", string.Empty), out TotalContributorsNumberValue);
}

return new Repository(OpenIssuesNumberValue, OpenPullRequestsNumberValue, TotalCommitsNumberValue, TotalContributorsNumberValue, baseData.User, baseData.RespositoryLink, baseData.RespositoryName, baseData.Description, baseData.TotalStars, baseData.TotalForks, baseData.HasProjectUrl, baseData.ProjectUrl, baseData.HasTopics, baseData.Topics);
}

internal static async Task<TrendItem> GetTrendDetails(TrendItem entryItem)
{
entryItem.HasDetails = true;
Expand All @@ -93,7 +183,7 @@ internal static async Task<TrendItem> GetTrendDetails(TrendItem entryItem)
if (ProjectUrl != null)
{
entryItem.HasProjectUrl = true;
entryItem.ProjectUrl = ProjectUrl.Attributes["href"].Value;
entryItem.ProjectUrl = ProjectUrl.GetAttributeValue("href", string.Empty);
}

if (Topics.Count > 0)
Expand Down
33 changes: 9 additions & 24 deletions GithubNet/TrendItem.cs → GithubNet/Models/ItemBase.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
namespace GithubNet
namespace GithubNet.Models
{
public class TrendItem
public class ItemBase
{
public TrendItem()
{
}

public TrendItem(string user, string respositoryLink, string respositoryName, string description, string totalStars, string totalForks, string programminglanguage)
public ItemBase(string user, string respositoryLink, string respositoryName, string description, int totalStars, int totalForks, bool hasProjectUrl, string projectUrl, bool hasTopics, string[] topics)
{
User = user;
RespositoryLink = respositoryLink;
RespositoryName = respositoryName;
Description = description;
TotalStars = totalStars;
TotalForks = totalForks;
Programminglanguage = programminglanguage;
HasProjectUrl = hasProjectUrl;
ProjectUrl = projectUrl;
HasTopics = hasTopics;
Topics = topics;
}

public string User { get; set; }
Expand All @@ -25,15 +24,9 @@ public TrendItem(string user, string respositoryLink, string respositoryName, st

public string Description { get; set; }

public string TotalStars { get; set; }

public string TotalForks { get; set; }

public string Programminglanguage { get; set; }
public int TotalStars { get; set; }

public bool HasDetails { get; set; }

public bool IsArchived { get; set; }
public int TotalForks { get; set; }

public bool HasProjectUrl { get; set; }

Expand All @@ -43,9 +36,6 @@ public TrendItem(string user, string respositoryLink, string respositoryName, st

public string[] Topics { get; set; }

public string LastCommitTime { get; set; }

public string LastCommitUrl { get; set; }

public string GetLastCommitUrl(string branch)
{
Expand All @@ -71,10 +61,5 @@ public string GetStarsUrl()
{
return $"https://github.com/{this.User}/{this.RespositoryName}/stargazers";
}

public override string ToString()
{
return $"{{{nameof(User)}={User}, {nameof(RespositoryLink)}={RespositoryLink}, {nameof(RespositoryName)}={RespositoryName}, {nameof(Description)}={Description}, {nameof(TotalStars)}={TotalStars}, {nameof(TotalForks)}={TotalForks}, {nameof(Programminglanguage)}={Programminglanguage}, {nameof(HasDetails)}={HasDetails.ToString()}, {nameof(IsArchived)}={IsArchived.ToString()}, {nameof(HasProjectUrl)}={HasProjectUrl.ToString()}, {nameof(ProjectUrl)}={ProjectUrl}, {nameof(HasTopics)}={HasTopics.ToString()}, {nameof(Topics)}={Topics}, {nameof(LastCommitTime)}={LastCommitTime}, {nameof(LastCommitUrl)}={LastCommitUrl}}}";
}
}
}
38 changes: 38 additions & 0 deletions GithubNet/Models/Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace GithubNet.Models
{
public class Repository : ItemBase
{
public Repository(int openIssuesNumber, int openPullRequestsNumber, int totalCommitsNumber, int totalContributorsNumber, string user, string respositoryLink, string respositoryName, string description, int totalStars, int totalForks, bool hasProjectUrl, string projectUrl, bool hasTopics, string[] topics) : base(user, respositoryLink, respositoryName, description, totalStars, totalForks, hasProjectUrl, projectUrl, hasTopics, topics)
{
OpenIssuesNumber = openIssuesNumber;
OpenPullRequestsNumber = openPullRequestsNumber;
TotalCommitsNumber = totalCommitsNumber;
TotalContributorsNumber = totalContributorsNumber;

base.User = user;
base.RespositoryLink = respositoryLink;
base.RespositoryName = respositoryName;
base.Description = description;
base.TotalStars = totalStars;
base.TotalForks = totalForks;
base.HasProjectUrl = hasProjectUrl;
base.ProjectUrl = projectUrl;
base.HasTopics = hasTopics;
base.Topics = topics;

}

public int OpenIssuesNumber { get; set; }

public int OpenPullRequestsNumber { get; set; }

public int TotalCommitsNumber { get; set; }

public int TotalContributorsNumber { get; set; }

public override string ToString()
{
return $"{{{nameof(OpenIssuesNumber)}={OpenIssuesNumber.ToString()}, {nameof(OpenPullRequestsNumber)}={OpenPullRequestsNumber.ToString()}, {nameof(TotalCommitsNumber)}={TotalCommitsNumber.ToString()}, {nameof(TotalContributorsNumber)}={TotalContributorsNumber.ToString()}, {nameof(User)}={User}, {nameof(RespositoryLink)}={RespositoryLink}, {nameof(RespositoryName)}={RespositoryName}, {nameof(Description)}={Description}, {nameof(TotalStars)}={TotalStars.ToString()}, {nameof(TotalForks)}={TotalForks.ToString()}, {nameof(HasProjectUrl)}={HasProjectUrl.ToString()}, {nameof(ProjectUrl)}={ProjectUrl}, {nameof(HasTopics)}={HasTopics.ToString()}, {nameof(Topics)}={Topics}}}";
}
}
}
36 changes: 36 additions & 0 deletions GithubNet/Models/TrendItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace GithubNet.Models
{
public class TrendItem : ItemBase
{

public TrendItem(string programminglanguage, bool hasDetails, bool isArchived, string lastCommitTime, string lastCommitUrl, string user, string respositoryLink, string respositoryName, string description, int totalStars, int totalForks, bool hasProjectUrl, string projectUrl, bool hasTopics, string[] topics) : base(user, respositoryLink, respositoryName, description, totalStars, totalForks, hasProjectUrl, projectUrl, hasTopics, topics)
{
Programminglanguage = programminglanguage;
HasDetails = hasDetails;
IsArchived = isArchived;
LastCommitTime = lastCommitTime;
LastCommitUrl = lastCommitUrl;
base.User = user;
base.RespositoryLink = respositoryLink;
base.RespositoryName = respositoryName;
base.Description = description;
base.TotalStars = totalStars;
base.TotalForks = totalForks;
base.HasProjectUrl = hasProjectUrl;
base.ProjectUrl = projectUrl;
base.HasTopics = hasTopics;
base.Topics = topics;
}

public string Programminglanguage { get; set; }

public bool HasDetails { get; set; }

public bool IsArchived { get; set; }

public string LastCommitTime { get; set; }

public string LastCommitUrl { get; set; }

}
}
5 changes: 4 additions & 1 deletion GithubNetDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GithubNet;
using GithubNet.Models;

namespace GithubNetDemo
{
Expand All @@ -8,8 +9,10 @@ private static async Task Main(string[] args)
{
GithubNetClient client = new();

List<TrendItem> testEntries = await client.GetTrendItemsAsync();
Repository tinygrad = await client.GetRepositoryInfoAsync("https://github.com/liebki/GithubNet");
Console.WriteLine(tinygrad.ToString());

List<TrendItem> testEntries = await client.GetTrendItemsAsync();
foreach (TrendItem entry in testEntries)
{
Console.WriteLine();
Expand Down
Loading

0 comments on commit a0e72df

Please sign in to comment.