diff --git a/CHANGELOG.md b/CHANGELOG.md
index 226b262..ea27952 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
 
 *a,c,f,r,o*
 
+## [6.0.13] - 23.03.2025
+
+### Added
+- Added `.linkfix <old> <new>` command
+    - If bot sees a message with the old link, it will reply to the message with a fixed (new) link
+    - ex: `.linkfix twitter.com vxtwitter.com`
+- Added `.roleicon role <icon_url / server_emoji>` command to set the icon of a role
+- Added a captcha option for `.fish`
+
+### Fixed
+- fixed youtube stream notifications in case invalid channel was provided
+- `.lcha` (live channel) will now let you override an existing channel template even if you're at the limit
+
+### Removed
+- removed `.xpglb` as it is no longer used
+
 ## [6.0.12] - 20.03.2025
 
 ### Fixed
diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj
index 1af72b5..ed3b6dc 100644
--- a/src/EllieBot/EllieBot.csproj
+++ b/src/EllieBot/EllieBot.csproj
@@ -4,7 +4,7 @@
         <Nullable>enable</Nullable>
         <ImplicitUsings>true</ImplicitUsings>
         <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
-        <Version>6.0.12</Version>
+        <Version>6.0.13</Version>
 
         <!-- Output/build -->
         <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>
diff --git a/src/EllieBot/Modules/Administration/Role/RoleCommands.cs b/src/EllieBot/Modules/Administration/Role/RoleCommands.cs
index b6b0eb0..0706166 100644
--- a/src/EllieBot/Modules/Administration/Role/RoleCommands.cs
+++ b/src/EllieBot/Modules/Administration/Role/RoleCommands.cs
@@ -48,9 +48,9 @@ public partial class Administration
                     });
 
                 await Response()
-                      .Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
-                          Format.Bold(targetUser.ToString())))
-                      .SendAsync();
+                    .Confirm(strs.setrole(Format.Bold(roleToAdd.Name),
+                        Format.Bold(targetUser.ToString())))
+                    .SendAsync();
             }
             catch (Exception ex)
             {
@@ -73,9 +73,9 @@ public partial class Administration
             {
                 await targetUser.RemoveRoleAsync(roleToRemove);
                 await Response()
-                      .Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
-                          Format.Bold(targetUser.ToString())))
-                      .SendAsync();
+                    .Confirm(strs.remrole(Format.Bold(roleToRemove.Name),
+                        Format.Bold(targetUser.ToString())))
+                    .SendAsync();
             }
             catch
             {
@@ -226,8 +226,8 @@ public partial class Administration
             if (!await CheckRoleHierarchy(role))
             {
                 await Response()
-                      .Error(strs.hierarchy)
-                      .SendAsync();
+                    .Error(strs.hierarchy)
+                    .SendAsync();
                 return;
             }
 
@@ -236,10 +236,83 @@ public partial class Administration
 
 
             await Response()
-                  .Confirm(strs.temp_role_added(user.Mention,
-                      Format.Bold(role.Name),
-                      TimestampTag.FromDateTime(DateTime.UtcNow.Add(timespan.Time), TimestampTagStyles.Relative)))
-                  .SendAsync();
+                .Confirm(strs.temp_role_added(user.Mention,
+                    Format.Bold(role.Name),
+                    TimestampTag.FromDateTime(DateTime.UtcNow.Add(timespan.Time), TimestampTagStyles.Relative)))
+                .SendAsync();
+        }
+
+        [Cmd]
+        [RequireContext(ContextType.Guild)]
+        [UserPerm(GuildPerm.ManageRoles)]
+        [BotPerm(GuildPerm.ManageRoles)]
+        public Task RoleIcon(IRole role, Emote emote)
+            => RoleIcon(role, emote.Url);
+
+        [Cmd]
+        [RequireContext(ContextType.Guild)]
+        [UserPerm(GuildPerm.ManageRoles)]
+        [BotPerm(GuildPerm.ManageRoles)]
+        public async Task RoleIcon(IRole role, [Leftover] string iconUrl)
+        {
+            if (!await CheckRoleHierarchy(role))
+                return;
+
+            if (string.IsNullOrWhiteSpace(iconUrl))
+            {
+                await Response().Error(strs.userrole_icon_invalid).SendAsync();
+                return;
+            }
+
+            // Validate the URL format
+            if (!Uri.TryCreate(iconUrl, UriKind.Absolute, out var uri))
+            {
+                await Response().Error(strs.userrole_icon_invalid).SendAsync();
+                return;
+            }
+
+            // Download the image
+            using var httpClient = new HttpClient();
+            using var response = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
+
+            // Check if the response is successful
+            if (!response.IsSuccessStatusCode)
+            {
+                await Response().Error(strs.userrole_icon_fail).SendAsync();
+                return;
+            }
+
+            // Check content type - must be image/png or image/jpeg
+            var contentType = response.Content.Headers.ContentType?.MediaType?.ToLower();
+            if (contentType != "image/png"
+                && contentType != "image/jpeg"
+                && contentType != "image/webp")
+            {
+                await Response().Error(strs.userrole_icon_fail).SendAsync();
+                return;
+            }
+
+            // Check file size - Discord limit is 256KB
+            var contentLength = response.Content.Headers.ContentLength;
+            if (contentLength is > 256 * 1024)
+            {
+                await Response().Error(strs.userrole_icon_fail).SendAsync();
+                return;
+            }
+
+            // Save the image to a memory stream
+            await using var stream = await response.Content.ReadAsStreamAsync();
+            await using var memoryStream = new MemoryStream();
+            await stream.CopyToAsync(memoryStream);
+            memoryStream.Position = 0;
+
+            // Create Discord image from stream
+            using var discordImage = new Image(memoryStream);
+
+            // Upload the image to Discord
+            await role.ModifyAsync(r => r.Icon = discordImage);
+
+            await Response().Confirm(strs.userrole_icon_success(Format.Bold(role.Name))).SendAsync();
         }
     }
 }
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/LinkFixer/LinkFixerService.cs b/src/EllieBot/Modules/Utility/LinkFixer/LinkFixerService.cs
index cf8ba82..3aed904 100644
--- a/src/EllieBot/Modules/Utility/LinkFixer/LinkFixerService.cs
+++ b/src/EllieBot/Modules/Utility/LinkFixer/LinkFixerService.cs
@@ -30,8 +30,8 @@ public partial class LinkFixerService(DbService db) : IReadyExecutor, IExecNoCom
 
     public async Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
     {
-        if(guild is null)
-        return;
+        if (guild is null)
+            return;
 
         var guildId = guild.Id;
         if (!_guildLinkFixes.TryGetValue(guildId, out var guildDict))
@@ -52,7 +52,7 @@ public partial class LinkFixerService(DbService db) : IReadyExecutor, IExecNoCom
             if (string.IsNullOrWhiteSpace(domain))
                 continue;
 
-            if(!guildDict.TryGetValue(domain, out var newDomain))
+            if (!guildDict.TryGetValue(domain, out var newDomain))
                 continue;
 
             var newUrl = match.Groups["prefix"].Value + newDomain + match.Groups["suffix"].Value;
@@ -73,10 +73,10 @@ public partial class LinkFixerService(DbService db) : IReadyExecutor, IExecNoCom
     public async Task<bool> AddLinkFixAsync(ulong guildId, string oldDomain, string newDomain)
     {
         oldDomain = oldDomain.ToLowerInvariant();
-        
+
         var guildDict = _guildLinkFixes.GetOrAdd(guildId, _ => new ConcurrentDictionary<string, string>());
         guildDict[oldDomain] = newDomain;
-        
+
         await using var uow = db.GetDbContext();
         await uow.GetTable<LinkFix>()
             .InsertOrUpdateAsync(() => new LinkFix
@@ -107,7 +107,7 @@ public partial class LinkFixerService(DbService db) : IReadyExecutor, IExecNoCom
     public async Task<bool> RemoveLinkFixAsync(ulong guildId, string oldDomain)
     {
         oldDomain = oldDomain.ToLowerInvariant();
-        
+
         if (!_guildLinkFixes.TryGetValue(guildId, out var guildDict) || !guildDict.TryRemove(oldDomain, out _))
             return false;
 
diff --git a/src/EllieBot/Modules/Utility/UserRole/UserRoleService.cs b/src/EllieBot/Modules/Utility/UserRole/UserRoleService.cs
index d500cb0..8718b08 100644
--- a/src/EllieBot/Modules/Utility/UserRole/UserRoleService.cs
+++ b/src/EllieBot/Modules/Utility/UserRole/UserRoleService.cs
@@ -154,7 +154,7 @@ public sealed class UserRoleService : IUserRoleService, IEService
             memoryStream.Position = 0;
 
             // Create Discord image from stream
-            var discordImage = new Image(memoryStream);
+            using var discordImage = new Image(memoryStream);
 
             // Upload the image to Discord
             var discordSuccess = await _discordRoleManager.ModifyRoleAsync(
diff --git a/src/EllieBot/data/commandlist.json b/src/EllieBot/data/commandlist.json
index c1d01ca..a023e3e 100644
--- a/src/EllieBot/data/commandlist.json
+++ b/src/EllieBot/data/commandlist.json
@@ -1606,6 +1606,21 @@
         "Administrator Server Permission"
       ]
     },
+    {
+      "Aliases": [
+        ".roleicon"
+      ],
+      "Description": "Changes the icon of a role.",
+      "Usage": [
+        ".roleicon @Role :server_emoji_here:"
+      ],
+      "Submodule": "RoleCommands",
+      "Module": "Administration",
+      "Options": null,
+      "Requirements": [
+        "ManageRoles Server Permission"
+      ]
+    },
     {
       "Aliases": [
         ".iam"
@@ -7384,6 +7399,37 @@
         "ManageChannels Channel Permission"
       ]
     },
+    {
+      "Aliases": [
+        ".linkfix",
+        ".lfix"
+      ],
+      "Description": "Configures automatic link fixing from one site to another.\nWhen a user posts a link containing the old domain, the bot will automatically fix it to use the new domain.\nProvide no second domain to disable link fixing.",
+      "Usage": [
+        ".linkfix twitter.com vxtwitter.com",
+        ".linkfix x.com"
+      ],
+      "Submodule": "LinkFixerCommands",
+      "Module": "Utility",
+      "Options": null,
+      "Requirements": [
+        "ManageMessages Server Permission"
+      ]
+    },
+    {
+      "Aliases": [
+        ".linkfixlist",
+        ".lfixlist"
+      ],
+      "Description": "Lists all configured link fixes for the server.",
+      "Usage": [
+        ".linkfixlist"
+      ],
+      "Submodule": "LinkFixerCommands",
+      "Module": "Utility",
+      "Options": null,
+      "Requirements": []
+    },
     {
       "Aliases": [
         ".livechadd",
@@ -8218,7 +8264,7 @@
       ],
       "Description": "Changes the icon of your assigned role.",
       "Usage": [
-        ".userroleicon @Role :thumbsup:"
+        ".userroleicon @Role :server_emoji_here:"
       ],
       "Submodule": "UserRoleCommands",
       "Module": "Utility",
diff --git a/src/EllieBot/data/fish.yml b/src/EllieBot/data/fish.yml
index 9bc1c7f..e07fee1 100644
--- a/src/EllieBot/data/fish.yml
+++ b/src/EllieBot/data/fish.yml
@@ -21,24 +21,24 @@ chance:
 fish:
   - id: 0
     name: Bass
-    weather:
-    spot:
-    time:
+    weather: 
+    spot: 
+    time: 
     chance: 100
     stars: 4
     fluff: Very common.
-    condition:
+    condition: 
     image: https://cdn.nadeko.bot/fish/bass.png
     emoji: <:bass:1328520376892002386>
 trash:
   - id: 1002
     name: Plastic Bag
-    weather:
-    spot:
-    time:
+    weather: 
+    spot: 
+    time: 
     chance: 50
     stars: 4
     fluff: Trophy of your contribution to the environment.
-    condition:
+    condition: 
     image: https://cdn.nadeko.bot/fish/plasticbag.png
-    emoji: <:plasticbag:1328520895454515211>
\ No newline at end of file
+    emoji: <:plasticbag:1328520895454515211>
diff --git a/src/EllieBot/strings/aliases.yml b/src/EllieBot/strings/aliases.yml
index 112c63c..1948ae4 100644
--- a/src/EllieBot/strings/aliases.yml
+++ b/src/EllieBot/strings/aliases.yml
@@ -165,6 +165,8 @@ deleterole:
 rolecolor:
   - rolecolor
   - roleclr
+roleicon:
+  - roleicon
 ban:
   - ban
   - b
diff --git a/src/EllieBot/strings/commands/commands.en-US.yml b/src/EllieBot/strings/commands/commands.en-US.yml
index 9eb73a1..24fee76 100644
--- a/src/EllieBot/strings/commands/commands.en-US.yml
+++ b/src/EllieBot/strings/commands/commands.en-US.yml
@@ -599,6 +599,20 @@ rolehoist:
   params:
     - role:
         desc: "The role that determines the visibility of the sidebar."
+roleicon:
+  desc: |-
+    Changes the icon of a role.
+  ex:
+    - '@Role :server_emoji_here:'
+  params:
+    - role:
+        desc: 'The role to change the icon of.'
+      imageUrl:
+        desc: 'The image url to be used as a new icon for the role.'
+    - role:
+        desc: 'The role to change the icon of.'
+      serverEmoji:
+        desc: 'The server emoji to be used as a new icon for the role.'
 createrole:
   desc: Creates a role with a given name.
   ex:
@@ -5054,7 +5068,7 @@ userroleicon:
   desc: |-
     Changes the icon of your assigned role.
   ex:
-    - '@Role :thumbsup:'
+    - '@Role :server_emoji_here:'
   params:
     - role:
         desc: 'The assigned role to change the icon of.'