Compare commits
29 Commits
Author | SHA1 | Date |
---|---|---|
Akamaru | 77f6928c9e | |
Andreas Bielawski | 594b8be769 | |
Andreas Bielawski | 4dcd67f71b | |
Akamaru | 6729c09010 | |
Andreas Bielawski | e97bea90e9 | |
Andreas Bielawski | e39f0969b0 | |
Akamaru | ca825ca7cb | |
Andreas Bielawski | e8b2c0dc60 | |
Akamaru | 5437cb2ab2 | |
Akamaru | 2bc253ed4f | |
Akamaru | 29a59bc33c | |
Andreas Bielawski | 403dd11fa9 | |
Akamaru | c728f62946 | |
Andreas Bielawski | a44d4b27a3 | |
Andreas Bielawski | 262d77d1e1 | |
Akamaru | 4994417c3d | |
Andreas Bielawski | 24ee7f9052 | |
Andreas Bielawski | 605475bc61 | |
Akamaru | a77fb812eb | |
Andreas Bielawski | bf3e8a65e1 | |
Andreas Bielawski | 30cdf087cc | |
Andreas | af1ae0883c | |
Andreas | 85dc187d51 | |
Andreas | b8ffe648ca | |
Andreas | 54183c534a | |
Andreas | fb36bf8dff | |
Andreas | 24bfffa7fa | |
Andreas | 1ccac01c0a | |
Andreas Bielawski | 3df3bfb261 |
|
@ -0,0 +1,51 @@
|
|||
name: CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 3.1.101
|
||||
- name: Build linux-x64
|
||||
run: dotnet publish -c debug -r linux-x64 /p:PublishSingleFile=true
|
||||
- name: Build linux-arm
|
||||
run: dotnet publish -c debug -r linux-arm /p:PublishSingleFile=true
|
||||
- name: Build win-x64
|
||||
run: dotnet publish -c debug -r win-x64 /p:PublishSingleFile=true
|
||||
- name: Build osx-x64
|
||||
run: dotnet publish -c debug -r osx-x64 /p:PublishSingleFile=true
|
||||
- name: Upload linux-x64
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
# Artifact name
|
||||
name: RSSBot-linux-x64-${{github.sha}}
|
||||
# Directory containing files to upload
|
||||
path: bin/Debug/netcoreapp3.1/linux-x64/publish/
|
||||
- name: Upload linux-arm
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
# Artifact name
|
||||
name: RSSBot-linux-arm-${{github.sha}}
|
||||
# Directory containing files to upload
|
||||
path: bin/Debug/netcoreapp3.1/linux-arm/publish/
|
||||
- name: Upload win-x64
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
# Artifact name
|
||||
name: RSSBot-win-x64-${{github.sha}}
|
||||
# Directory containing files to upload
|
||||
path: bin/Debug/netcoreapp3.1/win-x64/publish/
|
||||
- name: Upload osx-x64
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
# Artifact name
|
||||
name: RSSBot-osx-x64-${{github.sha}}
|
||||
# Directory containing files to upload
|
||||
path: bin/Debug/netcoreapp3.1/osx-x64/publish/
|
43
Bot.cs
43
Bot.cs
|
@ -19,7 +19,8 @@ namespace RSSBot {
|
|||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
private static HashSet<RegexHandler> Handlers;
|
||||
|
||||
private static void Main(string[] args) {
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Configuration.Parse();
|
||||
BotClient = new TelegramBotClient(Configuration.BotToken);
|
||||
try {
|
||||
|
@ -40,7 +41,8 @@ namespace RSSBot {
|
|||
new RegexHandler($"^/start(?:@{BotInfo.Username})?$", Commands.Welcome),
|
||||
new RegexHandler($"^/help(?:@{BotInfo.Username})?$", Commands.Help),
|
||||
new RegexHandler($"^/rss(?:@{BotInfo.Username})?$", Commands.Show),
|
||||
new RegexHandler($"^/rss(?:@{BotInfo.Username})? (@?[A-z0-9_]+)$", Commands.Show),
|
||||
new RegexHandler($"^/rss(?:@{BotInfo.Username})? (@[A-z0-9_]+)$", Commands.Show),
|
||||
new RegexHandler($@"^/rss(?:@{BotInfo.Username})? (-\d+)$", Commands.Show),
|
||||
new RegexHandler(
|
||||
$"^/show(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)$",
|
||||
Commands.ShowAvailableFeeds),
|
||||
|
@ -48,14 +50,20 @@ namespace RSSBot {
|
|||
$"^/sub(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)$",
|
||||
Commands.Subscribe),
|
||||
new RegexHandler(
|
||||
$"^/sub(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (@?[A-z0-9_]+)$$",
|
||||
$"^/sub(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (@[A-z0-9_]+)$",
|
||||
Commands.Subscribe),
|
||||
new RegexHandler(
|
||||
$@"^/sub(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (-\d+)$",
|
||||
Commands.Subscribe),
|
||||
new RegexHandler(
|
||||
$"^/del(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)$",
|
||||
Commands.Unsubscribe),
|
||||
new RegexHandler(
|
||||
$"^/del(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (@?[A-z0-9_]+)$$",
|
||||
$"^/del(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (@[A-z0-9_]+)$",
|
||||
Commands.Unsubscribe),
|
||||
new RegexHandler(
|
||||
$@"^/del(?:@{BotInfo.Username})? (http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&~+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+) (-\d+)$",
|
||||
Commands.Unsubscribe)
|
||||
};
|
||||
|
||||
JobQueue = new Timer(e => { Commands.Sync(); }, null, TimeSpan.FromSeconds(5),
|
||||
|
@ -70,7 +78,8 @@ namespace RSSBot {
|
|||
Save();
|
||||
}
|
||||
|
||||
private static void ReadAllFeeds() {
|
||||
private static void ReadAllFeeds()
|
||||
{
|
||||
RedisValue[] allFeedUrls = Configuration.Database.SetMembers($"{Configuration.RedisHash}:feeds");
|
||||
foreach (RedisValue feedUrl in allFeedUrls) {
|
||||
HashSet<long> subs = new HashSet<long>();
|
||||
|
@ -86,13 +95,18 @@ namespace RSSBot {
|
|||
}
|
||||
}
|
||||
|
||||
private static void OnProcessExit(object? sender, EventArgs e) {
|
||||
private static void OnProcessExit(object? sender, EventArgs e)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
private static void Bot_OnMessage(object? sender, MessageEventArgs messageEventArgs) {
|
||||
var message = messageEventArgs.Message;
|
||||
if (message == null || message.Type != MessageType.Text) return;
|
||||
private static void Bot_OnMessage(object? sender, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
Message message = messageEventArgs.Message;
|
||||
if (message == null || message.Type != MessageType.Text) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Configuration.Admins.Contains(message.From.Id)) {
|
||||
return;
|
||||
}
|
||||
|
@ -102,14 +116,17 @@ namespace RSSBot {
|
|||
}
|
||||
}
|
||||
|
||||
public static async void Save() {
|
||||
public static async void Save()
|
||||
{
|
||||
if (RssBotFeeds.Count > 0) {
|
||||
Logger.Info("Speichere Daten...");
|
||||
/* Logger.Info("Speichere Daten..."); */
|
||||
}
|
||||
|
||||
foreach (RssBotFeed feed in RssBotFeeds) {
|
||||
string feedKey = $"{Configuration.RedisHash}:{feed.Url}";
|
||||
if (string.IsNullOrWhiteSpace(feed.LastEntry)) continue;
|
||||
if (string.IsNullOrWhiteSpace(feed.LastEntry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await Configuration.Database.HashSetAsync(feedKey, "last_entry", feed.LastEntry);
|
||||
foreach (long chatId in feed.Subs) {
|
||||
|
@ -119,7 +136,7 @@ namespace RSSBot {
|
|||
await Configuration.Database.SetAddAsync($"{Configuration.RedisHash}:feeds", feed.Url);
|
||||
}
|
||||
|
||||
Logger.Info("Gespeichert!");
|
||||
/* Logger.Info("Gespeichert!"); */
|
||||
}
|
||||
}
|
||||
}
|
182
Commands.cs
182
Commands.cs
|
@ -1,7 +1,11 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using CodeHollow.FeedReader;
|
||||
using NLog;
|
||||
|
@ -13,15 +17,17 @@ namespace RSSBot {
|
|||
public static class Commands {
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public static async void Welcome(Message message, GroupCollection matches) {
|
||||
public static async void Welcome(Message message, GroupCollection matches)
|
||||
{
|
||||
await Bot.BotClient.SendTextMessageAsync(
|
||||
message.Chat,
|
||||
"<b>Willkommen beim RSS-Bot!</b>\nSende /help, um zu starten.",
|
||||
"<b>Willkommen bei RikoBot!</b>\nSende /help, um zu starten.",
|
||||
ParseMode.Html
|
||||
);
|
||||
}
|
||||
|
||||
public static async void Help(Message message, GroupCollection matches) {
|
||||
public static async void Help(Message message, GroupCollection matches)
|
||||
{
|
||||
await Bot.BotClient.SendTextMessageAsync(
|
||||
message.Chat,
|
||||
"<b>/rss</b> <i>[Chat]</i>: Abonnierte Feeds anzeigen\n" +
|
||||
|
@ -33,7 +39,8 @@ namespace RSSBot {
|
|||
);
|
||||
}
|
||||
|
||||
public static async void Subscribe(Message message, GroupCollection args) {
|
||||
public static async void Subscribe(Message message, GroupCollection args)
|
||||
{
|
||||
string url = args[1].Value;
|
||||
long chatId = message.Chat.Id;
|
||||
RssBotFeed feed = new RssBotFeed(url);
|
||||
|
@ -41,16 +48,24 @@ namespace RSSBot {
|
|||
await Bot.BotClient.SendChatActionAsync(message.Chat, ChatAction.Typing);
|
||||
|
||||
if (args.Count > 2) {
|
||||
string chatName = args[2].Value;
|
||||
if (!chatName.StartsWith("@")) {
|
||||
chatName = $"@{chatName}";
|
||||
}
|
||||
Chat chatInfo;
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
string chatName = args[2].Value;
|
||||
bool isId = long.TryParse(chatName, out chatId);
|
||||
|
||||
if (isId) {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatId);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chatId = chatInfo.Id;
|
||||
|
@ -91,23 +106,32 @@ namespace RSSBot {
|
|||
}
|
||||
}
|
||||
|
||||
public static async void Unsubscribe(Message message, GroupCollection args) {
|
||||
public static async void Unsubscribe(Message message, GroupCollection args)
|
||||
{
|
||||
string url = args[1].Value;
|
||||
long chatId = message.Chat.Id;
|
||||
RssBotFeed feed = Bot.RssBotFeeds
|
||||
.FirstOrDefault(x => x.Url.ToLower().Equals(url.ToLower()));
|
||||
|
||||
if (args.Count > 2) {
|
||||
string chatName = args[2].Value;
|
||||
if (!chatName.StartsWith("@")) {
|
||||
chatName = $"@{chatName}";
|
||||
}
|
||||
Chat chatInfo;
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
string chatName = args[2].Value;
|
||||
bool isId = long.TryParse(chatName, out chatId);
|
||||
|
||||
if (isId) {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatId);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chatId = chatInfo.Id;
|
||||
|
@ -133,23 +157,31 @@ namespace RSSBot {
|
|||
Bot.Save();
|
||||
}
|
||||
|
||||
public static async void Show(Message message, GroupCollection args) {
|
||||
public static async void Show(Message message, GroupCollection args)
|
||||
{
|
||||
long chatId = message.Chat.Id;
|
||||
string chatTitle = message.Chat.Type.Equals(ChatType.Private) ? message.Chat.FirstName : message.Chat.Title;
|
||||
await Bot.BotClient.SendChatActionAsync(message.Chat, ChatAction.Typing);
|
||||
|
||||
if (args.Count > 1) {
|
||||
string chatName = args[1].Value;
|
||||
if (!chatName.StartsWith("@")) {
|
||||
chatName = $"@{chatName}";
|
||||
}
|
||||
Chat chatInfo;
|
||||
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
if (args.Count > 1) {
|
||||
Chat chatInfo;
|
||||
string chatName = args[1].Value;
|
||||
bool isId = long.TryParse(chatName, out chatId);
|
||||
|
||||
if (isId) {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatId);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
chatInfo = await Bot.BotClient.GetChatAsync(chatName);
|
||||
} catch {
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, "❌ Dieser Kanal existiert nicht.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
chatId = chatInfo.Id;
|
||||
|
@ -161,24 +193,25 @@ namespace RSSBot {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string text;
|
||||
|
||||
List<RssBotFeed> feeds = Bot.RssBotFeeds.Where(x => x.Subs.Contains(chatId)).ToList();
|
||||
|
||||
StringBuilder text = new StringBuilder();
|
||||
if (feeds.Count < 1) {
|
||||
text = "❌ Keine Feeds abonniert.";
|
||||
text.Append("❌ Keine Feeds abonniert.");
|
||||
} else {
|
||||
text = $"<strong>{HttpUtility.HtmlEncode(chatTitle)}</strong> hat abonniert:\n";
|
||||
text.Append($"<strong>{HttpUtility.HtmlEncode(chatTitle)}</strong> hat abonniert:\n");
|
||||
for (int i = 0; i < feeds.Count; i++) {
|
||||
text += $"<strong>{i + 1}</strong>) {feeds[i].Url}\n";
|
||||
text.Append($"<strong>{i + 1}</strong>) {feeds[i].Url}\n");
|
||||
}
|
||||
}
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, text, ParseMode.Html, true);
|
||||
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, text.ToString(), ParseMode.Html, true);
|
||||
}
|
||||
|
||||
public static async void Sync() {
|
||||
Logger.Info(("================================"));
|
||||
public static async void Sync()
|
||||
{
|
||||
Logger.Info("================================");
|
||||
bool hadEntries = false;
|
||||
foreach (RssBotFeed feed in Bot.RssBotFeeds.ToList()) {
|
||||
Logger.Info(feed.Url);
|
||||
|
@ -190,7 +223,7 @@ namespace RSSBot {
|
|||
}
|
||||
|
||||
if (feed.NewEntries.Count == 0) {
|
||||
Logger.Info("Keine neuen Beiträge.");
|
||||
/* Logger.Info("Keine neuen Beiträge."); */
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -203,6 +236,7 @@ namespace RSSBot {
|
|||
string postTitle = "Kein Titel";
|
||||
if (!string.IsNullOrWhiteSpace(entry.Title)) {
|
||||
postTitle = Utils.StripHtml(entry.Title);
|
||||
postTitle = Utils.EscapeHtml(postTitle);
|
||||
}
|
||||
|
||||
string postLink = feed.MainLink;
|
||||
|
@ -211,46 +245,34 @@ namespace RSSBot {
|
|||
postLink = entry.Link;
|
||||
// FeedProxy URLs
|
||||
GroupCollection feedProxy =
|
||||
Utils.ReturnMatches(postLink, "^https?://feedproxy.google.com/~r/(.+)/.*");
|
||||
Utils.ReturnMatches(postLink, "^https?://feedproxy.google.com/~r/(.+?)/.*");
|
||||
linkName = feedProxy.Count > 1 ? feedProxy[1].Value : new Uri(postLink).Host;
|
||||
}
|
||||
|
||||
// Remove "www."
|
||||
int index = linkName.IndexOf("www.", StringComparison.Ordinal);
|
||||
if (index > 0) {
|
||||
if (index > -1) {
|
||||
linkName = linkName.Remove(index, 4);
|
||||
}
|
||||
|
||||
string content = "";
|
||||
if (!string.IsNullOrWhiteSpace(entry.Content)) {
|
||||
content = Utils.ProcessContent(entry.Content); // magic processing missing
|
||||
content = Utils.ProcessContent(entry.Content);
|
||||
} else if (!string.IsNullOrWhiteSpace(entry.Description)) {
|
||||
content = Utils.ProcessContent(entry.Description);
|
||||
}
|
||||
|
||||
string text = $"<b>{postTitle}</b>\n<i>{feed.Title}</i>\n{content}";
|
||||
text += $"\n<a href=\"{postLink}\">Weiterlesen auf {linkName}</a>";
|
||||
string text = $"<b>[#RSS] {postTitle}</b>\n{content}";
|
||||
text += $"\n<a href=\"{postLink}\">Auf {linkName} ansehen.</a>";
|
||||
|
||||
// Send
|
||||
foreach (long chatId in feed.Subs.ToList()) {
|
||||
try {
|
||||
await Bot.BotClient.SendTextMessageAsync(chatId, text, ParseMode.Html, true, true);
|
||||
} catch (ApiRequestException e) {
|
||||
if (e.ErrorCode.Equals(403)) {
|
||||
Logger.Warn(e.Message);
|
||||
feed.Cleanup(chatId);
|
||||
if (feed.Subs.Count == 0) { // was last subscriber
|
||||
Bot.RssBotFeeds.Remove(feed);
|
||||
}
|
||||
} else {
|
||||
Logger.Error($"{e.ErrorCode}: {e.Message}");
|
||||
}
|
||||
}
|
||||
await SendFinishedMessage(chatId, text, feed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info("Nächster Check in 60 Sekunden");
|
||||
/* Logger.Info("Nächster Check in 60 Sekunden"); */
|
||||
|
||||
if (hadEntries) {
|
||||
Bot.Save();
|
||||
|
@ -259,7 +281,32 @@ namespace RSSBot {
|
|||
Bot.JobQueue.Change(TimeSpan.FromMinutes(1), TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
|
||||
public static async void ShowAvailableFeeds(Message message, GroupCollection args) {
|
||||
private static async Task SendFinishedMessage(long chatId, string text, RssBotFeed feed, int waitTime = 10)
|
||||
{
|
||||
try {
|
||||
await Bot.BotClient.SendTextMessageAsync(chatId, text, ParseMode.Html, true, true);
|
||||
Thread.Sleep(1000);
|
||||
} catch (ApiRequestException e) {
|
||||
if (e.ErrorCode.Equals(403)) {
|
||||
Logger.Warn(e.Message);
|
||||
feed.Cleanup(chatId);
|
||||
if (feed.Subs.Count == 0) // was last subscriber
|
||||
{
|
||||
Bot.RssBotFeeds.Remove(feed);
|
||||
}
|
||||
} else {
|
||||
Logger.Error($"{e.ErrorCode}: {e.Message}");
|
||||
}
|
||||
} catch (HttpRequestException) // likely 429
|
||||
{
|
||||
Logger.Warn($"Rate-Limit erreicht, warte {waitTime} Sekunden...");
|
||||
Thread.Sleep(waitTime * 1000);
|
||||
await SendFinishedMessage(chatId, text, feed, waitTime * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public static async void ShowAvailableFeeds(Message message, GroupCollection args)
|
||||
{
|
||||
string url = args[1].Value;
|
||||
IEnumerable<HtmlFeedLink> feeds;
|
||||
try {
|
||||
|
@ -276,7 +323,8 @@ namespace RSSBot {
|
|||
}
|
||||
|
||||
string text = htmlFeedLinks.Aggregate("Feeds gefunden:\n",
|
||||
(current, feedLink) => current + $"* <a href=\"{feedLink.Url}\">{Utils.StripHtml(feedLink.Title)}</a>\n");
|
||||
(current, feedLink) =>
|
||||
current + $"* <a href=\"{feedLink.Url}\">{Utils.StripHtml(feedLink.Title)}</a>\n");
|
||||
|
||||
await Bot.BotClient.SendTextMessageAsync(message.Chat, text, ParseMode.Html, true);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ namespace RSSBot {
|
|||
public static List<int> Admins;
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public static void Parse() {
|
||||
public static void Parse()
|
||||
{
|
||||
if (!File.Exists("NLog.config")) {
|
||||
Console.WriteLine("NLog.config nicht gefunden, setze auf INFO...");
|
||||
LoggingConfiguration config = new LoggingConfiguration();
|
||||
|
|
11
README.md
11
README.md
|
@ -1,11 +1,12 @@
|
|||
RSS Bot for Telegram
|
||||
=====================
|
||||
1. **Install .NET Core Runtime >= 3.1 and Redis**
|
||||
2. **Copy config:** `cp config.ini.example config.ini`
|
||||
3. **Insert bot token** in `config.ini`
|
||||
2. Download the bot from the [Releases](https://github.com/Brawl345/RSSBot-Sharp/releases) section
|
||||
3. **Copy config:** `cp config.ini.example config.ini`
|
||||
4. **Insert bot token** in `config.ini`
|
||||
1. Adjust Redis settings if needed
|
||||
4. **Insert your Telegram ID as admin** (send `@Brawlbot id` inside a chat to get yours)
|
||||
5. Optional: Copy the `NLog.config.example` next to the config.ini as `NLog.config`
|
||||
6. Run the `RSSBot` executable
|
||||
5. **Insert your Telegram ID as admin** (send `@Brawlbot id` inside a chat to get yours)
|
||||
6. Optional: Copy the `NLog.config.example` next to the config.ini as `NLog.config`
|
||||
7. Run the `RSSBot` executable
|
||||
|
||||
(c) 2020 Andreas Bielawski
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64;linux-arm</RuntimeIdentifiers>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<!-- <PublishReadyToRun>true</PublishReadyToRun>-->
|
||||
<!-- <PublishSingleFile>true</PublishSingleFile>-->
|
||||
<SelfContained>false</SelfContained>
|
||||
|
@ -18,8 +18,8 @@
|
|||
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.1" />
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="NLog" Version="4.6.8" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.0.601" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.2.0" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.1.58" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.7.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -4,38 +4,41 @@ using Telegram.Bot.Types;
|
|||
|
||||
namespace RSSBot {
|
||||
/// <summary>
|
||||
/// RegexHandler for Telegram Bots.
|
||||
/// RegexHandler for Telegram Bots.
|
||||
/// </summary>
|
||||
public class RegexHandler {
|
||||
private string Pattern;
|
||||
private Action<Message, GroupCollection> CallbackFunction;
|
||||
private readonly Action<Message, GroupCollection> CallbackFunction;
|
||||
private readonly string Pattern;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the RegexHandler.
|
||||
/// Constructor for the RegexHandler.
|
||||
/// </summary>
|
||||
/// <param name="pattern">Regex pattern</param>
|
||||
/// <param name="callback">Callback function to call when the update should be processed</param>
|
||||
public RegexHandler(string pattern, Action<Message, GroupCollection> callback) {
|
||||
public RegexHandler(string pattern, Action<Message, GroupCollection> callback)
|
||||
{
|
||||
Pattern = pattern;
|
||||
CallbackFunction = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the update should be handled by this handler.
|
||||
/// Checks whether the update should be handled by this handler.
|
||||
/// </summary>
|
||||
/// <param name="message">Telegram Message object</param>
|
||||
/// <returns>true if the update should be handled</returns>
|
||||
public bool HandleUpdate(Message message) {
|
||||
public bool HandleUpdate(Message message)
|
||||
{
|
||||
return Regex.IsMatch(message.Text,
|
||||
Pattern,
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls the assoicated callback function.
|
||||
/// Calls the assoicated callback function.
|
||||
/// </summary>
|
||||
/// <param name="message">Telegram Message object</param>
|
||||
public void ProcessUpdate(Message message) {
|
||||
public void ProcessUpdate(Message message)
|
||||
{
|
||||
GroupCollection matches = Regex.Match(message.Text,
|
||||
Pattern,
|
||||
RegexOptions.IgnoreCase
|
||||
|
|
|
@ -6,14 +6,12 @@ using CodeHollow.FeedReader;
|
|||
|
||||
namespace RSSBot {
|
||||
public class RssBotFeed {
|
||||
public readonly HashSet<long> Subs = new HashSet<long>();
|
||||
public readonly string Url;
|
||||
public string LastEntry;
|
||||
public readonly HashSet<long> Subs = new HashSet<long>();
|
||||
public string MainLink { get; private set; }
|
||||
public string Title { get; private set; }
|
||||
public List<FeedItem> NewEntries { get; private set; }
|
||||
|
||||
public RssBotFeed(string url, string lastEntry = null, HashSet<long> subs = null) {
|
||||
|
||||
public RssBotFeed(string url, string lastEntry = null, HashSet<long> subs = null)
|
||||
{
|
||||
Url = url;
|
||||
if (!string.IsNullOrWhiteSpace(lastEntry)) {
|
||||
LastEntry = lastEntry;
|
||||
|
@ -24,7 +22,12 @@ namespace RSSBot {
|
|||
}
|
||||
}
|
||||
|
||||
public async Task Check() {
|
||||
public string MainLink { get; private set; }
|
||||
public string Title { get; private set; }
|
||||
public List<FeedItem> NewEntries { get; private set; }
|
||||
|
||||
public async Task Check()
|
||||
{
|
||||
Feed feed = await FeedReader.ReadAsync(Url);
|
||||
if (string.IsNullOrWhiteSpace(feed.Link)) {
|
||||
throw new Exception("Kein gültiger RSS-Feed.");
|
||||
|
@ -33,7 +36,10 @@ namespace RSSBot {
|
|||
MainLink = feed.Link;
|
||||
Title = feed.Title;
|
||||
|
||||
if (feed.Items == null || feed.Items.Count <= 0) return;
|
||||
if (feed.Items == null || feed.Items.Count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NewEntries = string.IsNullOrWhiteSpace(LastEntry)
|
||||
? feed.Items.ToList()
|
||||
: GetNewEntries(feed.Items);
|
||||
|
@ -43,7 +49,8 @@ namespace RSSBot {
|
|||
: feed.Items.First().Id;
|
||||
}
|
||||
|
||||
private List<FeedItem> GetNewEntries(IEnumerable<FeedItem> entries) {
|
||||
private List<FeedItem> GetNewEntries(IEnumerable<FeedItem> entries)
|
||||
{
|
||||
List<FeedItem> newEntries = new List<FeedItem>();
|
||||
foreach (FeedItem entry in entries) {
|
||||
if (!string.IsNullOrWhiteSpace(entry.Id)) {
|
||||
|
@ -65,17 +72,22 @@ namespace RSSBot {
|
|||
return newEntries;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
public override string ToString()
|
||||
{
|
||||
return $"RSS-Feed: '{Url}'";
|
||||
}
|
||||
|
||||
public void Cleanup(long chatId) {
|
||||
public void Cleanup(long chatId)
|
||||
{
|
||||
Subs.Remove(chatId);
|
||||
string feedKey = $"{Configuration.RedisHash}:{Url}";
|
||||
Configuration.Database.SetRemove($"{feedKey}:subs", chatId);
|
||||
|
||||
// No subscribers, delete all references
|
||||
if (Subs.Count != 0 || !Configuration.Database.KeyExists(feedKey)) return;
|
||||
if (Subs.Count != 0 || !Configuration.Database.KeyExists(feedKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Configuration.Database.KeyDelete(feedKey);
|
||||
Configuration.Database.KeyDelete($"{feedKey}:subs");
|
||||
Configuration.Database.SetRemove($"{Configuration.RedisHash}:feeds", Url);
|
||||
|
|
57
Utils.cs
57
Utils.cs
|
@ -1,19 +1,32 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace RSSBot {
|
||||
public static class Utils {
|
||||
public static string StripHtml(string input) {
|
||||
return Regex.Replace(input, "<.*?>", String.Empty).Trim();
|
||||
private static readonly Regex RegexHtml = new Regex("<.*?>");
|
||||
|
||||
public static string StripHtml(string input)
|
||||
{
|
||||
return RegexHtml.Replace(input, string.Empty).Trim();
|
||||
}
|
||||
|
||||
private static string CleanRss(string input) {
|
||||
public static string EscapeHtml(string input)
|
||||
{
|
||||
input = input.Replace("<", "<");
|
||||
input = input.Replace(">", ">");
|
||||
return input;
|
||||
}
|
||||
|
||||
private static string CleanRss(string input)
|
||||
{
|
||||
string[] replacements = {
|
||||
"[←]",
|
||||
"[…]",
|
||||
"[...]",
|
||||
"[bilder]",
|
||||
"[boerse]",
|
||||
"[mehr]",
|
||||
|
@ -36,20 +49,28 @@ namespace RSSBot {
|
|||
"Read more »",
|
||||
"Read more",
|
||||
"...Read More",
|
||||
"...mehr lesen",
|
||||
"mehr lesen",
|
||||
"(more…)",
|
||||
"View On WordPress",
|
||||
"Continue reading →",
|
||||
"» weiterlesen",
|
||||
"Ein Kommentar.",
|
||||
"Änderungen zeigen",
|
||||
"(Feed generated with FetchRSS)",
|
||||
"(RSS generated with FetchRss)",
|
||||
"-- Delivered by Feed43 service",
|
||||
"Meldung bei www.tagesschau.de lesen"
|
||||
};
|
||||
|
||||
string[] regexReplacements = {
|
||||
"Der Beitrag.*erschien zuerst auf .+.",
|
||||
"The post.*appeared first on .+.",
|
||||
"http://www.serienjunkies.de/.*.html"
|
||||
"http://www.serienjunkies.de/.*.html",
|
||||
"Nächstältere Version.*",
|
||||
"Die Seite wurde neu angelegt.*",
|
||||
"Weiterleitung nach.*erstellt.*"
|
||||
};
|
||||
|
||||
input = input.Replace("\n", " ");
|
||||
input = replacements.Aggregate(input, (current, replacement) => current.Replace(replacement, ""));
|
||||
input = regexReplacements.Aggregate(input,
|
||||
(current, replacement) => Regex.Replace(current, replacement, ""));
|
||||
|
@ -57,8 +78,9 @@ namespace RSSBot {
|
|||
return input;
|
||||
}
|
||||
|
||||
public static string ProcessContent(string input) {
|
||||
string content = StripHtml(input);
|
||||
public static string ProcessContent(string input)
|
||||
{
|
||||
string content = StripHtml(HttpUtility.HtmlDecode(input));
|
||||
content = CleanRss(content);
|
||||
if (content.Length > 250) {
|
||||
content = content.Substring(0, 250) + "...";
|
||||
|
@ -67,23 +89,18 @@ namespace RSSBot {
|
|||
return content;
|
||||
}
|
||||
|
||||
public static bool IsCommand(string messageText, string command) {
|
||||
return Regex.Match(messageText,
|
||||
$"^/{command}(?:@{Bot.BotInfo.Username})?$",
|
||||
RegexOptions.IgnoreCase
|
||||
).Success;
|
||||
}
|
||||
|
||||
public static GroupCollection ReturnMatches(string text, string pattern) {
|
||||
public static GroupCollection ReturnMatches(string text, string pattern)
|
||||
{
|
||||
return Regex.Match(text,
|
||||
pattern,
|
||||
RegexOptions.IgnoreCase
|
||||
).Groups;
|
||||
}
|
||||
|
||||
public static async Task<bool> IsBotAdmin(long chatId) {
|
||||
public static async Task<bool> IsBotAdmin(long chatId)
|
||||
{
|
||||
ChatMember chatMember = await Bot.BotClient.GetChatMemberAsync(chatId, Bot.BotClient.BotId);
|
||||
return chatMember.Status.Equals(ChatMemberStatus.Administrator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue