mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Added .stondel which makes the bot delete stream online messages after the stream goes offline
This commit is contained in:
		@@ -92,6 +92,7 @@ public class GuildConfig : DbEntity
 | 
			
		||||
    public List<FeedSub> FeedSubs { get; set; } = new();
 | 
			
		||||
    public IndexedCollection<ReactionRoleMessage> ReactionRoleMessages { get; set; } = new();
 | 
			
		||||
    public bool NotifyStreamOffline { get; set; }
 | 
			
		||||
    public bool DeleteStreamOnlineMessage { get; set; }
 | 
			
		||||
    public List<GroupName> SelfAssignableRoleGroupNames { get; set; }
 | 
			
		||||
    public int WarnExpireHours { get; set; }
 | 
			
		||||
    public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2759
									
								
								src/NadekoBot/Migrations/Sqlite/20220427200557_stondel.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2759
									
								
								src/NadekoBot/Migrations/Sqlite/20220427200557_stondel.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										26
									
								
								src/NadekoBot/Migrations/Sqlite/20220427200557_stondel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/NadekoBot/Migrations/Sqlite/20220427200557_stondel.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Migrations;
 | 
			
		||||
 | 
			
		||||
#nullable disable
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Migrations
 | 
			
		||||
{
 | 
			
		||||
    public partial class stondel : Migration
 | 
			
		||||
    {
 | 
			
		||||
        protected override void Up(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.AddColumn<bool>(
 | 
			
		||||
                name: "DeleteStreamOnlineMessage",
 | 
			
		||||
                table: "GuildConfigs",
 | 
			
		||||
                type: "INTEGER",
 | 
			
		||||
                nullable: false,
 | 
			
		||||
                defaultValue: false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void Down(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.DropColumn(
 | 
			
		||||
                name: "DeleteStreamOnlineMessage",
 | 
			
		||||
                table: "GuildConfigs");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -809,6 +809,9 @@ namespace NadekoBot.Migrations
 | 
			
		||||
                    b.Property<bool>("DeleteMessageOnCommand")
 | 
			
		||||
                        .HasColumnType("INTEGER");
 | 
			
		||||
 | 
			
		||||
                    b.Property<bool>("DeleteStreamOnlineMessage")
 | 
			
		||||
                        .HasColumnType("INTEGER");
 | 
			
		||||
 | 
			
		||||
                    b.Property<string>("DmGreetMessageText")
 | 
			
		||||
                        .HasColumnType("TEXT");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -121,6 +121,18 @@ public partial class Searches
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_off_disabled);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [UserPerm(GuildPerm.ManageMessages)]
 | 
			
		||||
        public async partial Task StreamOnlineDelete()
 | 
			
		||||
        {
 | 
			
		||||
            var newValue = _service.ToggleStreamOnlineDelete(ctx.Guild.Id);
 | 
			
		||||
            if (newValue)
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_online_delete_enabled);
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalizedAsync(strs.stream_online_delete_disabled);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Cmd]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
using LinqToDB;
 | 
			
		||||
using LinqToDB.EntityFrameworkCore;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Db;
 | 
			
		||||
@@ -24,6 +26,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<StreamDataKey, Dictionary<ulong, HashSet<FollowedStream>>> _shardTrackedStreams;
 | 
			
		||||
    private readonly ConcurrentHashSet<ulong> _offlineNotificationServers;
 | 
			
		||||
    private readonly ConcurrentHashSet<ulong> _deleteOnOfflineServers;
 | 
			
		||||
 | 
			
		||||
    private readonly IPubSub _pubSub;
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
@@ -33,6 +36,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
    private readonly TypedKey<FollowStreamPubData> _streamFollowKey;
 | 
			
		||||
    private readonly TypedKey<FollowStreamPubData> _streamUnfollowKey;
 | 
			
		||||
    private readonly ConnectionMultiplexer _redis;
 | 
			
		||||
 | 
			
		||||
    public StreamNotificationService(
 | 
			
		||||
        DbService db,
 | 
			
		||||
@@ -50,6 +54,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
        _strings = strings;
 | 
			
		||||
        _pubSub = pubSub;
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _redis = redis;
 | 
			
		||||
        _streamTracker = new(httpFactory, creds, redis, creds.GetCreds().RedisKey(), client.ShardId == 0);
 | 
			
		||||
 | 
			
		||||
        _streamsOnlineKey = new("streams.online");
 | 
			
		||||
@@ -71,6 +76,11 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
                                              .Where(gc => gc.NotifyStreamOffline)
 | 
			
		||||
                                              .Select(x => x.GuildId)
 | 
			
		||||
                                              .ToList());
 | 
			
		||||
            
 | 
			
		||||
            _deleteOnOfflineServers = new(guildConfigs
 | 
			
		||||
                                              .Where(gc => gc.DeleteStreamOnlineMessage)
 | 
			
		||||
                                              .Select(x => x.GuildId)
 | 
			
		||||
                                              .ToList());
 | 
			
		||||
 | 
			
		||||
            var followedStreams = guildConfigs.SelectMany(x => x.FollowedStreams).ToList();
 | 
			
		||||
 | 
			
		||||
@@ -243,6 +253,44 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
                      .WhenAll();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (_client.ShardId == 0)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var stream in offlineStreams)
 | 
			
		||||
            {
 | 
			
		||||
                await DeleteOnlineMessages(stream);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task DeleteOnlineMessages(StreamData stream)
 | 
			
		||||
    {
 | 
			
		||||
        var db = _redis.GetDatabase();
 | 
			
		||||
        var data = await db.ListRangeAsync($"streams_online_del:{stream.CreateKey()}");
 | 
			
		||||
        await db.KeyDeleteAsync($"streams_online_del:{stream.CreateKey()}");
 | 
			
		||||
        
 | 
			
		||||
        foreach (string pair in data)
 | 
			
		||||
        {
 | 
			
		||||
            var pairArr = pair.Split(',');
 | 
			
		||||
            if (pairArr.Length != 2)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            if (!ulong.TryParse(pairArr[0], out var chId) || !ulong.TryParse(pairArr[1], out var msgId))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var textChannel = await _client.GetChannelAsync(chId) as ITextChannel;
 | 
			
		||||
                if (textChannel is null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                await textChannel.DeleteMessageAsync(msgId);
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async ValueTask HandleStreamsOnline(List<StreamData> onlineStreams)
 | 
			
		||||
@@ -252,13 +300,13 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
            var key = stream.CreateKey();
 | 
			
		||||
            if (_shardTrackedStreams.TryGetValue(key, out var fss))
 | 
			
		||||
            {
 | 
			
		||||
                await fss.SelectMany(x => x.Value)
 | 
			
		||||
                         .Select(fs =>
 | 
			
		||||
                var messages = await fss.SelectMany(x => x.Value)
 | 
			
		||||
                         .Select(async fs =>
 | 
			
		||||
                         {
 | 
			
		||||
                             var textChannel = _client.GetGuild(fs.GuildId)?.GetTextChannel(fs.ChannelId);
 | 
			
		||||
 | 
			
		||||
                             if (textChannel is null)
 | 
			
		||||
                                 return Task.CompletedTask;
 | 
			
		||||
                                 return default;
 | 
			
		||||
 | 
			
		||||
                             var rep = new ReplacementBuilder().WithOverride("%user%", () => fs.Username)
 | 
			
		||||
                                                               .WithOverride("%platform%", () => fs.Type.ToString())
 | 
			
		||||
@@ -266,9 +314,38 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                             var message = string.IsNullOrWhiteSpace(fs.Message) ? "" : rep.Replace(fs.Message);
 | 
			
		||||
 | 
			
		||||
                             return textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream), message);
 | 
			
		||||
                             var msg = await textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream), message);
 | 
			
		||||
 | 
			
		||||
                             // only cache the ids of channel/message pairs 
 | 
			
		||||
                             if(_deleteOnOfflineServers.Contains(fs.GuildId))
 | 
			
		||||
                                return (textChannel.Id, msg.Id);
 | 
			
		||||
                             else 
 | 
			
		||||
                                 return default;
 | 
			
		||||
                         })
 | 
			
		||||
                         .WhenAll();
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                // push online stream messages to redis
 | 
			
		||||
                // when streams go offline, any server which
 | 
			
		||||
                // has the online stream message deletion feature
 | 
			
		||||
                // enabled will have the online messages deleted
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var pairs = messages
 | 
			
		||||
                                .Where(x => x != default)
 | 
			
		||||
                                .Select(x => (RedisValue)$"{x.Item1},{x.Item2}")
 | 
			
		||||
                                .ToArray();
 | 
			
		||||
 | 
			
		||||
                    if (pairs.Length > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        var db = _redis.GetDatabase();
 | 
			
		||||
                        await db.ListRightPushAsync($"streams_online_del:{key}", pairs);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -484,6 +561,21 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
        return newValue;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public bool ToggleStreamOnlineDelete(ulong guildId)
 | 
			
		||||
    {
 | 
			
		||||
        using var uow = _db.GetDbContext();
 | 
			
		||||
        var gc = uow.GuildConfigsForId(guildId, set => set);
 | 
			
		||||
        var newValue = gc.DeleteStreamOnlineMessage = !gc.DeleteStreamOnlineMessage;
 | 
			
		||||
        uow.SaveChanges();
 | 
			
		||||
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            _deleteOnOfflineServers.Add(guildId);
 | 
			
		||||
        else
 | 
			
		||||
            _deleteOnOfflineServers.TryRemove(guildId);
 | 
			
		||||
 | 
			
		||||
        return newValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task<StreamData> GetStreamDataAsync(string url)
 | 
			
		||||
        => _streamTracker.GetStreamDataByUrlAsync(url);
 | 
			
		||||
 
 | 
			
		||||
@@ -518,6 +518,9 @@ streamoffline:
 | 
			
		||||
- streamoffline
 | 
			
		||||
- sto
 | 
			
		||||
- stoff
 | 
			
		||||
streamonlinedelete:
 | 
			
		||||
- streamonlinedelte
 | 
			
		||||
- stondel
 | 
			
		||||
streammessage:
 | 
			
		||||
- streammsg
 | 
			
		||||
- stm
 | 
			
		||||
 
 | 
			
		||||
@@ -912,6 +912,10 @@ streamoffline:
 | 
			
		||||
  desc: "Toggles whether the bot will also notify when added streams go offline."
 | 
			
		||||
  args:
 | 
			
		||||
    - ""
 | 
			
		||||
streamonlinedelete:
 | 
			
		||||
  desc: "Toggles whether the bot will delete stream online message when the stream goes offline."
 | 
			
		||||
  args:
 | 
			
		||||
    - ""
 | 
			
		||||
streammessage:
 | 
			
		||||
  desc: "Sets the message which will show when the stream on the specified index comes online. You can use %user% and %platform% placeholders."
 | 
			
		||||
  args:
 | 
			
		||||
 
 | 
			
		||||
@@ -519,6 +519,8 @@
 | 
			
		||||
  "stream_no": "No such stream.",
 | 
			
		||||
  "stream_off_enabled": "Stream notifications will now show when a stream goes offline.",
 | 
			
		||||
  "stream_off_disabled": "Stream notifications will no longer show when a stream goes offline.",
 | 
			
		||||
  "stream_online_delete_enabled": "Online stream notifications will now be deleted when the stream goes offline.",
 | 
			
		||||
  "stream_online_delete_disabled": "Online stream notifications will no longer be deleted when the stream goes offline.",
 | 
			
		||||
  "stream_not_added": "Stream was not added. Either stream doesn't exist, that platform is unsupported, or you've reached the maximum number of streams allowed.",
 | 
			
		||||
  "stream_message_reset": "Announcement message for {0} stream has been reset.",
 | 
			
		||||
  "stream_message_set": "Announcement message when {0} stream goes online has been set.",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user