Collector jobs have been updated to handle authors
This commit is contained in:
parent
56a655e4f1
commit
0d751cc571
@ -30,6 +30,7 @@ public class CodeProjectWatcherJob
|
|||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
private IDiscordQueueRepository _queue;
|
private IDiscordQueueRepository _queue;
|
||||||
private ISourcesRepository _source;
|
private ISourcesRepository _source;
|
||||||
|
private IAuthorTable _author;
|
||||||
|
|
||||||
public CodeProjectWatcherJob()
|
public CodeProjectWatcherJob()
|
||||||
{
|
{
|
||||||
@ -37,12 +38,14 @@ public class CodeProjectWatcherJob
|
|||||||
_queue = new DiscordQueueTable("");
|
_queue = new DiscordQueueTable("");
|
||||||
_source = new SourcesTable("");
|
_source = new SourcesTable("");
|
||||||
_logger = JobLogger.GetLogger("", JobName);
|
_logger = JobLogger.GetLogger("", JobName);
|
||||||
|
_author = new AuthorsTable("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeProjectWatcherJob(CodeProjectWatcherJobOptions options)
|
public CodeProjectWatcherJob(CodeProjectWatcherJobOptions options)
|
||||||
{
|
{
|
||||||
options.ConnectionStrings ??= new ConfigSectionConnectionStrings();
|
options.ConnectionStrings ??= new ConfigSectionConnectionStrings();
|
||||||
_articles = new ArticlesTable(options.ConnectionStrings.Database ?? "");
|
_articles = new ArticlesTable(options.ConnectionStrings.Database ?? "");
|
||||||
|
_author = new AuthorsTable(options.ConnectionStrings.Database ?? "");
|
||||||
_queue = new DiscordQueueTable(options.ConnectionStrings.Database ?? "");
|
_queue = new DiscordQueueTable(options.ConnectionStrings.Database ?? "");
|
||||||
_source = new SourcesTable(options.ConnectionStrings.Database ?? "");
|
_source = new SourcesTable(options.ConnectionStrings.Database ?? "");
|
||||||
_logger = JobLogger.GetLogger(options.ConnectionStrings.OpenTelemetry ?? "", JobName);
|
_logger = JobLogger.GetLogger(options.ConnectionStrings.OpenTelemetry ?? "", JobName);
|
||||||
@ -52,6 +55,7 @@ public class CodeProjectWatcherJob
|
|||||||
{
|
{
|
||||||
options.ConnectionStrings ??= new ConfigSectionConnectionStrings();
|
options.ConnectionStrings ??= new ConfigSectionConnectionStrings();
|
||||||
_articles = new ArticlesTable(options.ConnectionStrings.Database ?? "");
|
_articles = new ArticlesTable(options.ConnectionStrings.Database ?? "");
|
||||||
|
_author = new AuthorsTable(options.ConnectionStrings.Database ?? "");
|
||||||
_queue = new DiscordQueueTable(options.ConnectionStrings.Database ?? "");
|
_queue = new DiscordQueueTable(options.ConnectionStrings.Database ?? "");
|
||||||
_source = new SourcesTable(options.ConnectionStrings.Database ?? "");
|
_source = new SourcesTable(options.ConnectionStrings.Database ?? "");
|
||||||
_logger = JobLogger.GetLogger(options.ConnectionStrings.OpenTelemetry ?? "", JobName);
|
_logger = JobLogger.GetLogger(options.ConnectionStrings.OpenTelemetry ?? "", JobName);
|
||||||
@ -157,17 +161,29 @@ public class CodeProjectWatcherJob
|
|||||||
});
|
});
|
||||||
parser.Parse();
|
parser.Parse();
|
||||||
|
|
||||||
|
if (item.Authors[0].Name is null)
|
||||||
|
{
|
||||||
|
_logger.Warning("Author was missing from the record and will continue with a missing author");
|
||||||
|
}
|
||||||
|
|
||||||
|
var authorExists = _author.CreateIfMissingAsync(new AuthorEntity
|
||||||
|
{
|
||||||
|
Name = item.Authors[0].Name,
|
||||||
|
SourceId = source.Id,
|
||||||
|
Image = "",
|
||||||
|
});
|
||||||
|
authorExists.Wait();
|
||||||
|
|
||||||
var a = new ArticlesEntity
|
var a = new ArticlesEntity
|
||||||
{
|
{
|
||||||
SourceId = source.Id,
|
SourceId = source.Id,
|
||||||
|
AuthorId = authorExists.Result.Id,
|
||||||
Tags = source.Tags,
|
Tags = source.Tags,
|
||||||
Title = item.Title.Text,
|
Title = item.Title.Text,
|
||||||
Url = itemUrl,
|
Url = itemUrl,
|
||||||
PubDate = item.LastUpdatedTime.DateTime,
|
PubDate = item.LastUpdatedTime.DateTime,
|
||||||
Thumbnail = parser.Data.Header.Image,
|
Thumbnail = parser.Data.Header.Image,
|
||||||
Description = item.Title.Text,
|
Description = item.Title.Text,
|
||||||
AuthorName = item.Authors[0].Name ?? "",
|
|
||||||
AuthorImage = item.Authors[0].Uri ?? "",
|
|
||||||
CodeIsRelease = isRelease,
|
CodeIsRelease = isRelease,
|
||||||
CodeIsCommit = isCommit,
|
CodeIsCommit = isCommit,
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,7 @@ public class DiscordNotificationJob
|
|||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
//private DatabaseContext _databaseContext;
|
//private DatabaseContext _databaseContext;
|
||||||
private IArticlesRepository _article;
|
private IArticlesRepository _article;
|
||||||
|
private IAuthorTable _author;
|
||||||
private IIconsRepository _icons;
|
private IIconsRepository _icons;
|
||||||
private IDiscordQueueRepository _queue;
|
private IDiscordQueueRepository _queue;
|
||||||
private ISourcesRepository _sources;
|
private ISourcesRepository _sources;
|
||||||
@ -46,6 +47,7 @@ public class DiscordNotificationJob
|
|||||||
{
|
{
|
||||||
_queue = new DiscordQueueTable("");
|
_queue = new DiscordQueueTable("");
|
||||||
_article = new ArticlesTable("");
|
_article = new ArticlesTable("");
|
||||||
|
_author = new AuthorsTable("");
|
||||||
_webhook = new DiscordWebhooksTable("");
|
_webhook = new DiscordWebhooksTable("");
|
||||||
_sources = new SourcesTable("");
|
_sources = new SourcesTable("");
|
||||||
_subs = new DiscordNotificationTable("");
|
_subs = new DiscordNotificationTable("");
|
||||||
@ -92,7 +94,6 @@ public class DiscordNotificationJob
|
|||||||
_logger.Debug($"{JobName} - Processing {request.Id}");
|
_logger.Debug($"{JobName} - Processing {request.Id}");
|
||||||
// Get all details on the article in the queue
|
// Get all details on the article in the queue
|
||||||
var articleDetails = _article.GetById(request.ArticleId);
|
var articleDetails = _article.GetById(request.ArticleId);
|
||||||
|
|
||||||
// Get the details of the source
|
// Get the details of the source
|
||||||
var sourceDetails = _sources.GetById(articleDetails.SourceId);
|
var sourceDetails = _sources.GetById(articleDetails.SourceId);
|
||||||
if (sourceDetails.Id == Guid.Empty)
|
if (sourceDetails.Id == Guid.Empty)
|
||||||
@ -103,6 +104,9 @@ public class DiscordNotificationJob
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var author = _author.GetBySourceIdAndNameAsync(sourceDetails.Id, sourceDetails.Name);
|
||||||
|
author.Wait();
|
||||||
|
|
||||||
var sourceIcon = new IconEntity();
|
var sourceIcon = new IconEntity();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -118,13 +122,13 @@ public class DiscordNotificationJob
|
|||||||
var allSubscriptions = _subs.ListBySourceId(sourceDetails.Id);
|
var allSubscriptions = _subs.ListBySourceId(sourceDetails.Id);
|
||||||
|
|
||||||
foreach (var sub in allSubscriptions)
|
foreach (var sub in allSubscriptions)
|
||||||
SendSubscriptionNotification(request.Id, articleDetails, sourceDetails, sourceIcon, sub);
|
SendSubscriptionNotification(request.Id, articleDetails, sourceDetails, sourceIcon, sub, author.Result ?? new AuthorEntity());
|
||||||
|
|
||||||
_logger.Debug("{JobName} - Removing {RequestId} from the queue", JobName, request.Id);
|
_logger.Debug("{JobName} - Removing {RequestId} from the queue", JobName, request.Id);
|
||||||
_queue.Delete(request.Id);
|
_queue.Delete(request.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendSubscriptionNotification(Guid requestId, ArticlesEntity articleDetails, SourceEntity sourceDetails, IconEntity sourceIcon, DiscordNotificationEntity sub)
|
public void SendSubscriptionNotification(Guid requestId, ArticlesEntity articleDetails, SourceEntity sourceDetails, IconEntity sourceIcon, DiscordNotificationEntity sub, AuthorEntity authorEntity)
|
||||||
{
|
{
|
||||||
// Check if the subscription code flags
|
// Check if the subscription code flags
|
||||||
// If the article is a code commit and the subscription does not want them, skip.
|
// If the article is a code commit and the subscription does not want them, skip.
|
||||||
@ -140,7 +144,7 @@ public class DiscordNotificationJob
|
|||||||
var client = new DiscordClient(discordDetails.Url);
|
var client = new DiscordClient(discordDetails.Url);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.SendMessage(GenerateDiscordMessage(sourceDetails, articleDetails, sourceIcon));
|
client.SendMessage(GenerateDiscordMessage(sourceDetails, articleDetails, sourceIcon, authorEntity));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -154,7 +158,7 @@ public class DiscordNotificationJob
|
|||||||
Thread.Sleep(3000);
|
Thread.Sleep(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiscordMessage GenerateDiscordMessage(SourceEntity source, ArticlesEntity article, IconEntity icon)
|
public DiscordMessage GenerateDiscordMessage(SourceEntity source, ArticlesEntity article, IconEntity icon, AuthorEntity author)
|
||||||
{
|
{
|
||||||
var embed = new DiscordMessageEmbed
|
var embed = new DiscordMessageEmbed
|
||||||
{
|
{
|
||||||
@ -163,7 +167,7 @@ public class DiscordNotificationJob
|
|||||||
Description = MessageValidation.ConvertHtmlCodes(article.Description),
|
Description = MessageValidation.ConvertHtmlCodes(article.Description),
|
||||||
Author = new DiscordMessageEmbedAuthor
|
Author = new DiscordMessageEmbedAuthor
|
||||||
{
|
{
|
||||||
Name = article.AuthorName,
|
Name = author.Name,
|
||||||
IconUrl = icon.FileName
|
IconUrl = icon.FileName
|
||||||
},
|
},
|
||||||
Footer = new DiscordMessageEmbedFooter
|
Footer = new DiscordMessageEmbedFooter
|
||||||
@ -189,7 +193,7 @@ public class DiscordNotificationJob
|
|||||||
Url = article.Thumbnail
|
Url = article.Thumbnail
|
||||||
};
|
};
|
||||||
|
|
||||||
if (article.AuthorImage is not null && article.AuthorImage != "") embed.Author.IconUrl = article.AuthorImage;
|
embed.Author.IconUrl = author.Image ?? "";
|
||||||
|
|
||||||
return new DiscordMessage
|
return new DiscordMessage
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,7 @@ public class YoutubeWatcherJob
|
|||||||
|
|
||||||
private readonly YoutubeWatcherJobOptions _options;
|
private readonly YoutubeWatcherJobOptions _options;
|
||||||
private IArticlesRepository _articles;
|
private IArticlesRepository _articles;
|
||||||
|
private IAuthorTable _author;
|
||||||
private IIconsRepository _icons;
|
private IIconsRepository _icons;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
private IDiscordQueueRepository _queue;
|
private IDiscordQueueRepository _queue;
|
||||||
@ -34,6 +35,7 @@ public class YoutubeWatcherJob
|
|||||||
{
|
{
|
||||||
_options = new YoutubeWatcherJobOptions();
|
_options = new YoutubeWatcherJobOptions();
|
||||||
_articles = new ArticlesTable("");
|
_articles = new ArticlesTable("");
|
||||||
|
_author = new AuthorsTable("");
|
||||||
_queue = new DiscordQueueTable("");
|
_queue = new DiscordQueueTable("");
|
||||||
_source = new SourcesTable("");
|
_source = new SourcesTable("");
|
||||||
_icons = new IconsTable("");
|
_icons = new IconsTable("");
|
||||||
@ -43,6 +45,7 @@ public class YoutubeWatcherJob
|
|||||||
public void InitAndExecute(YoutubeWatcherJobOptions options)
|
public void InitAndExecute(YoutubeWatcherJobOptions options)
|
||||||
{
|
{
|
||||||
_articles = new ArticlesTable(options.DatabaseConnectionString ?? "");
|
_articles = new ArticlesTable(options.DatabaseConnectionString ?? "");
|
||||||
|
_author = new AuthorsTable(options.DatabaseConnectionString ?? "");
|
||||||
_queue = new DiscordQueueTable(options.DatabaseConnectionString ?? "");
|
_queue = new DiscordQueueTable(options.DatabaseConnectionString ?? "");
|
||||||
_source = new SourcesTable(options.DatabaseConnectionString ?? "");
|
_source = new SourcesTable(options.DatabaseConnectionString ?? "");
|
||||||
_icons = new IconsTable(options.DatabaseConnectionString ?? "");
|
_icons = new IconsTable(options.DatabaseConnectionString ?? "");
|
||||||
@ -77,11 +80,23 @@ public class YoutubeWatcherJob
|
|||||||
_logger.Information($"{JobName} - Checking '{source.Name}'");
|
_logger.Information($"{JobName} - Checking '{source.Name}'");
|
||||||
var url = $"https://www.youtube.com/feeds/videos.xml?channel_id={channelId}";
|
var url = $"https://www.youtube.com/feeds/videos.xml?channel_id={channelId}";
|
||||||
|
|
||||||
var newVideos = CheckFeed(url, source);
|
var newVideos = FindMissingPosts(url, source);
|
||||||
_logger.Debug($"{JobName} - Collected {newVideos.Count} new videos");
|
_logger.Debug($"{JobName} - Collected {newVideos.Count} new videos");
|
||||||
|
|
||||||
foreach (var video in newVideos)
|
foreach (var video in newVideos)
|
||||||
{
|
{
|
||||||
_logger.Debug($"{JobName} - {video.AuthorName} '{video.Title}' was found");
|
var author = _author.GetById(video.AuthorId);
|
||||||
|
author.Wait();
|
||||||
|
|
||||||
|
if (author.Result is null)
|
||||||
|
{
|
||||||
|
_logger.Warning("Missing author record for article id {VideoId}", video.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("{JobName} - {ResultName} \'{VideoTitle}\' was found", JobName, author.Result.Name, video.Title);
|
||||||
|
}
|
||||||
|
|
||||||
_articles.New(video);
|
_articles.New(video);
|
||||||
_queue.New(new DiscordQueueEntity
|
_queue.New(new DiscordQueueEntity
|
||||||
{
|
{
|
||||||
@ -104,22 +119,31 @@ public class YoutubeWatcherJob
|
|||||||
|
|
||||||
var id = pageReader.Data.Header.YoutubeChannelID ?? "";
|
var id = pageReader.Data.Header.YoutubeChannelID ?? "";
|
||||||
if (id == "")
|
if (id == "")
|
||||||
_logger.Error(new Exception($"{JobName} - Unable to find the Youtube Channel ID for the requested url."),
|
_logger.Error(new Exception($"{JobName} - Unable to find the Youtube Channel ID for the requested url"), "");
|
||||||
url);
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ArticlesEntity> CheckFeed(string url, SourceEntity source)
|
private List<ArticlesEntity> FindMissingPosts(string url, SourceEntity source)
|
||||||
{
|
{
|
||||||
var videos = new List<ArticlesEntity>();
|
var videos = new List<ArticlesEntity>();
|
||||||
|
|
||||||
using var reader = XmlReader.Create(url);
|
using var reader = XmlReader.Create(url);
|
||||||
var feed = SyndicationFeed.Load(reader);
|
var feed = SyndicationFeed.Load(reader);
|
||||||
foreach (var post in feed.Items.ToList())
|
foreach (var post in feed.Items.ToList())
|
||||||
|
{
|
||||||
|
var article = CheckFeedItem(post, source.Id);
|
||||||
|
if (article is null) continue;
|
||||||
|
videos.Add(article);
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArticlesEntity? CheckFeedItem(SyndicationItem post, Guid sourceId)
|
||||||
{
|
{
|
||||||
var articleUrl = post.Links[0].Uri.AbsoluteUri;
|
var articleUrl = post.Links[0].Uri.AbsoluteUri;
|
||||||
if (IsThisUrlKnown(articleUrl)) continue;
|
if (IsThisUrlKnown(articleUrl)) return null;
|
||||||
|
|
||||||
var videoDetails = new HtmlPageReader(new HtmlPageReaderOptions
|
var videoDetails = new HtmlPageReader(new HtmlPageReaderOptions
|
||||||
{
|
{
|
||||||
@ -127,26 +151,28 @@ public class YoutubeWatcherJob
|
|||||||
});
|
});
|
||||||
videoDetails.Parse();
|
videoDetails.Parse();
|
||||||
|
|
||||||
|
var author = _author.CreateIfMissingAsync(new AuthorEntity
|
||||||
|
{
|
||||||
|
Image = post.Authors[0].Uri,
|
||||||
|
Name = post.Authors[0].Name
|
||||||
|
});
|
||||||
|
author.Wait();
|
||||||
|
|
||||||
var article = new ArticlesEntity
|
var article = new ArticlesEntity
|
||||||
{
|
{
|
||||||
//Todo add the icon
|
//Todo add the icon
|
||||||
AuthorName = post.Authors[0].Name,
|
AuthorId = author.Result.Id,
|
||||||
Title = post.Title.Text,
|
Title = post.Title.Text,
|
||||||
Tags = FetchTags(post),
|
Tags = FetchTags(post),
|
||||||
Url = articleUrl,
|
Url = articleUrl,
|
||||||
PubDate = post.PublishDate.DateTime,
|
PubDate = post.PublishDate.DateTime,
|
||||||
Thumbnail = videoDetails.Data.Header.Image,
|
Thumbnail = videoDetails.Data.Header.Image,
|
||||||
Description = videoDetails.Data.Header.Description,
|
Description = videoDetails.Data.Header.Description,
|
||||||
SourceId = source.Id,
|
SourceId = sourceId,
|
||||||
Video = "true"
|
Video = "true"
|
||||||
};
|
};
|
||||||
|
|
||||||
videos.Add(article);
|
return article;
|
||||||
|
|
||||||
Thread.Sleep(_options.SleepTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return videos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsThisUrlKnown(string url)
|
private bool IsThisUrlKnown(string url)
|
||||||
|
Loading…
Reference in New Issue
Block a user