using axXez.TS3.Protocol; using System.Collections.Generic; using System.Linq; namespace axXez.TS3.Bot.Modules { [Module(Namespace = "axXez", DisplayName = "User Channels")] internal class UserChannels : Module { public string ParentChannelName { get; set; } public string ChannelGroupName { get; set; } = "Channel Admin"; public string ChannelName { get; set; } = "Get your channel"; public string ChannelDescription { get; set; } = "By joining this channel you create your own temporary channel."; public int DeleteDelay { get; set; } = 3600; // 1h private Channel _parentChannel; private ChannelGroupInfo _channelGroup; private int _targetChannelId = -1; private Dictionary _userChannels; protected override void OnStart() { if (!Server.FindChannel(ParentChannelName, out _parentChannel)) return; if (!Server.FindChannelGroup(ChannelGroupName, out _channelGroup)) return; _userChannels = new(); var list = Query.ListClientsByChannelGroup(groupID: _channelGroup.ID); if (list != null) { foreach (var v in list) { if (_userChannels.ContainsKey(v.ClientDBID)) continue; if (!Server.FindChannel(v.ChannelID, out Channel channel)) continue; if (channel.ParentID != _parentChannel.ID) continue; _userChannels.Add(v.ClientDBID, channel.ID); Log($"Loaded existing channel for user DBID={v.ClientDBID} ID={channel.ID}"); } } if (!Server.FindChannel(ChannelName, out var targetChannel)) { CreateTargetChannel(); return; } _targetChannelId = targetChannel.ID; } protected override void OnStop(bool queryConnected) { if (_targetChannelId != -1) { Query.DeleteChannel(_targetChannelId); _targetChannelId = -1; } } protected override void OnUnload() { //base.OnUnload(); //don't auto save config } private void CreateTargetChannel() { _targetChannelId = Query.CreateChannel(new EditChannelProperties() { Name = ChannelName, SemiPermanentFlag = true, Description = ChannelDescription, ParentId = _parentChannel.ID }); Log($"Create new target channel ID={_targetChannelId}"); } private void CreateUserChannel(Client client) { Log($"Create channel for user '{client.Name}' ID={_targetChannelId}"); var userChannelId = _targetChannelId; _targetChannelId = -1; if (!Query.EditChannel(userChannelId, new() { Name = $"{client.Name}'s Channel", Description = $"userChannel:{client.DBID}", SemiPermanentFlag = false, DeleteDelay = DeleteDelay, })) return; if (!Query.SetClientChannelGroup(_channelGroup.ID, userChannelId, client.DBID)) return; _userChannels.Add(client.DBID, userChannelId); //create new target channel CreateTargetChannel(); } public override void OnClientMoved(Client client, Channel target, EventReason reason, Client invoker) { if (_targetChannelId == -1 || target.ID != _targetChannelId) return; Log($"Client joined target channel ClientID={client.ID}"); if (_userChannels.TryGetValue(client.DBID, out var userChannelId)) { Log($"Channel for user '{client.Name}' already exists ID={userChannelId}"); //user channel already exists -> move user to channel Query.MoveClient(client.ID, userChannelId); return; } CreateUserChannel(client); } public override void OnChannelDeleted(Channel channel, Client invoker) { foreach (var uc in _userChannels.Where(uc => uc.Value == channel.ID).ToList()) _userChannels.Remove(uc.Key); } [Command("uchannel status", Description = "Shows user channel configuration and active channels")] public CommandResponse Status(CommandContext ctx) { ctx.Reply("[B]User Channels[/B]"); ctx.Reply($" Parent channel: {(_parentChannel != null ? $"[B]{_parentChannel.Name}[/B]" : $"[B]{ParentChannelName}[/B] [COLOR=red](not found)[/COLOR]")}"); ctx.Reply($" Channel group: {(_channelGroup != null ? $"[B]{_channelGroup.Name}[/B]" : $"[B]{ChannelGroupName}[/B] [COLOR=red](not found)[/COLOR]")}"); ctx.Reply($" Trigger channel: [B]{ChannelName}[/B]"); ctx.Reply($" Delete delay: [B]{DeleteDelay}s[/B]"); return ctx.Ok($" Active user channels: [B]{_userChannels?.Count ?? 0}[/B]"); } [Command("uchannel delay", Description = "Gets or sets the delete delay in seconds", Role = CommandRole.Admin)] public CommandResponse Delay(CommandContext ctx, int seconds = -1, bool save = false) { if (seconds == -1) { return ctx.Ok($"Delete delay: [B]{DeleteDelay}s[/B]"); } DeleteDelay = seconds; if (save) Save(); ctx.Reply($"Delete delay set to [B]{seconds}s[/B]{(save ? " and saved." : ".")}"); return ctx.Ok(); } } }