diff --git a/tests/Recyclarr.Cli.IntegrationTests/CliCommandIntegrationTest.cs b/tests/Recyclarr.Cli.IntegrationTests/CliCommandIntegrationTest.cs
index 67fab971..e30d5698 100644
--- a/tests/Recyclarr.Cli.IntegrationTests/CliCommandIntegrationTest.cs
+++ b/tests/Recyclarr.Cli.IntegrationTests/CliCommandIntegrationTest.cs
@@ -16,7 +16,8 @@ internal class CliCommandIntegrationTest : CliIntegrationFixture
     {
         await Mapper.DownloadFiles(
             "metadata.json",
-            "docs/Radarr/Radarr-collection-of-custom-formats.md");
+            "docs/Radarr/Radarr-collection-of-custom-formats.md",
+            "docs/Sonarr/sonarr-collection-of-custom-formats.md");
     }
 
     [SetUp]
@@ -29,16 +30,10 @@ internal class CliCommandIntegrationTest : CliIntegrationFixture
     public async Task List_custom_format_radarr_score_sets()
     {
         var repo = Resolve<ITrashGuidesRepo>();
-        var cfPath = repo.Path.SubDirectory("docs/json/radarr/cf");
-        string[] cfs = ["4k-remaster.json", "10bit.json"];
-
-        foreach (var cf in cfs)
-        {
-            Fs.AddFileFromEmbeddedResource(
-                cfPath.File(cf),
-                typeof(CliCommandIntegrationTest),
-                $"Data/RadarrCustomFormats/{cf}");
-        }
+        Fs.AddFilesFromEmbeddedNamespace(
+            repo.Path.SubDirectory("docs/json/radarr/cf"),
+            typeof(CliCommandIntegrationTest),
+            "Data/radarr/cfs");
 
         var exitCode = await CliSetup.Run(Container, ["list", "custom-formats", "radarr", "--score-sets"]);
 
@@ -46,10 +41,40 @@ internal class CliCommandIntegrationTest : CliIntegrationFixture
         Console.Output.Should().ContainAll("default", "sqp-1-1080p", "sqp-1-2160p");
     }
 
+    [Test]
+    public async Task List_custom_format_sonarr_score_sets()
+    {
+        var repo = Resolve<ITrashGuidesRepo>();
+        Fs.AddFilesFromEmbeddedNamespace(
+            repo.Path.SubDirectory("docs/json/sonarr/cf"),
+            typeof(CliCommandIntegrationTest),
+            "Data/sonarr/cfs");
+
+        var exitCode = await CliSetup.Run(Container, ["list", "custom-formats", "sonarr", "--score-sets"]);
+
+        exitCode.Should().Be(0);
+        Console.Output.Should().ContainAll("default", "anime-sonarr", "french-multi");
+    }
+
     [Test]
     public async Task List_custom_format_score_sets_fails_without_service_type()
     {
         var act = () => CliSetup.Run(Container, ["list", "custom-formats", "--score-sets"]);
         await act.Should().ThrowAsync<CommandRuntimeException>();
     }
+
+    [Test]
+    public async Task List_naming_sonarr()
+    {
+        var repo = Resolve<ITrashGuidesRepo>();
+        Fs.AddFilesFromEmbeddedNamespace(
+            repo.Path.SubDirectory("docs/json/sonarr/naming"),
+            typeof(CliCommandIntegrationTest),
+            "Data/sonarr/naming");
+
+        var exitCode = await CliSetup.Run(Container, ["list", "naming", "sonarr"]);
+
+        exitCode.Should().Be(0);
+        Console.Output.Should().ContainAll("default", "plex-imdb", "original");
+    }
 }
diff --git a/tests/Recyclarr.Cli.IntegrationTests/Data/RadarrCustomFormats/10bit.json b/tests/Recyclarr.Cli.IntegrationTests/Data/radarr/cfs/10bit.json
similarity index 100%
rename from tests/Recyclarr.Cli.IntegrationTests/Data/RadarrCustomFormats/10bit.json
rename to tests/Recyclarr.Cli.IntegrationTests/Data/radarr/cfs/10bit.json
diff --git a/tests/Recyclarr.Cli.IntegrationTests/Data/RadarrCustomFormats/4k-remaster.json b/tests/Recyclarr.Cli.IntegrationTests/Data/radarr/cfs/4k-remaster.json
similarity index 100%
rename from tests/Recyclarr.Cli.IntegrationTests/Data/RadarrCustomFormats/4k-remaster.json
rename to tests/Recyclarr.Cli.IntegrationTests/Data/radarr/cfs/4k-remaster.json
diff --git a/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/bad-dual-groups.json b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/bad-dual-groups.json
new file mode 100644
index 00000000..25f4229c
--- /dev/null
+++ b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/bad-dual-groups.json
@@ -0,0 +1,236 @@
+{
+  "trash_id": "32b367365729d530ca1c124a0b180c64",
+  "trash_scores": {
+    "default": -10000,
+    "french-multi": 0
+  },
+  "name": "Bad Dual Groups",
+  "includeCustomFormatWhenRenaming": false,
+  "specifications": [
+    {
+      "name": "alfaHD",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(alfaHD.*)$"
+      }
+    },
+    {
+      "name": "BAT",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(BAT)$"
+      }
+    },
+    {
+      "name": "BlackBit",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(BlackBit)$"
+      }
+    },
+    {
+      "name": "BNd",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(BNd)$"
+      }
+    },
+    {
+      "name": "C.A.A",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(C\\.A\\.A)$"
+      }
+    },
+    {
+      "name": "Cory",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(Cory)$"
+      }
+    },
+    {
+      "name": "EXTREME",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(EXTREME)$"
+      }
+    },
+    {
+      "name": "FF",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(FF)$"
+      }
+    },
+    {
+      "name": "FOXX",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(FOXX)$"
+      }
+    },
+    {
+      "name": "G4RiS",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(G4RiS)$"
+      }
+    },
+    {
+      "name": "GUEIRA",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(GUEIRA)$"
+      }
+    },
+    {
+      "name": "LCD",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(LCD)$"
+      }
+    },
+    {
+      "name": "N3G4N",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(N3G4N)$"
+      }
+    },
+    {
+      "name": "PD",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(PD)$"
+      }
+    },
+    {
+      "name": "PTHome",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(PTHome)$"
+      }
+    },
+    {
+      "name": "RiPER",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(RiPER)$"
+      }
+    },
+    {
+      "name": "RK",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(RK)$"
+      }
+    },
+    {
+      "name": "SiGLA",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(SiGLA)$"
+      }
+    },
+    {
+      "name": "Tars",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(Tars)$"
+      }
+    },
+    {
+      "name": "vnlls",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(vnlls)$"
+      }
+    },
+    {
+      "name": "WTV",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(WTV)$"
+      }
+    },
+    {
+      "name": "Yatogam1",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(Yatogam1)$"
+      }
+    },
+    {
+      "name": "YusukeFLA",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(YusukeFLA)$"
+      }
+    },
+    {
+      "name": "ZigZag",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(ZigZag)$"
+      }
+    },
+    {
+      "name": "ZNM",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(ZNM)$"
+      }
+    }
+  ]
+}
diff --git a/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/web-tier-03.json b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/web-tier-03.json
new file mode 100644
index 00000000..49a4aafe
--- /dev/null
+++ b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/cfs/web-tier-03.json
@@ -0,0 +1,83 @@
+{
+  "trash_id": "d84935abd3f8556dcd51d4f27e22d0a6",
+  "trash_scores": {
+    "default": 1600,
+    "anime-sonarr": 150
+  },
+  "name": "WEB Tier 03",
+  "includeCustomFormatWhenRenaming": false,
+  "specifications": [
+    {
+      "name": "DRACULA",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(DRACULA)$"
+      }
+    },
+    {
+      "name": "NINJACENTRAL",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(NINJACENTRAL)$"
+      }
+    },
+    {
+      "name": "SLiGNOME",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(SLiGNOME)$"
+      }
+    },
+    {
+      "name": "SwAgLaNdEr",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(SwAgLaNdEr)$"
+      }
+    },
+    {
+      "name": "T4H",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(T4H)$"
+      }
+    },
+    {
+      "name": "ViSiON",
+      "implementation": "ReleaseGroupSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": "^(ViSiON)$"
+      }
+    },
+    {
+      "name": "WEBDL",
+      "implementation": "SourceSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": 3
+      }
+    },
+    {
+      "name": "WEBRIP",
+      "implementation": "SourceSpecification",
+      "negate": false,
+      "required": false,
+      "fields": {
+        "value": 4
+      }
+    }
+  ]
+}
diff --git a/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/naming/sonarr-naming.json b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/naming/sonarr-naming.json
new file mode 100644
index 00000000..2a537a6d
--- /dev/null
+++ b/tests/Recyclarr.Cli.IntegrationTests/Data/sonarr/naming/sonarr-naming.json
@@ -0,0 +1,22 @@
+{
+  "season": {
+    "default": "Season {season:00}"
+  },
+  "series": {
+    "default": "{Series TitleYear}",
+    "plex-imdb": "{Series TitleYear} {imdb-{ImdbId}}"
+  },
+  "episodes": {
+    "standard": {
+      "default": "{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoCodec]}{-Release Group}",
+      "original": "{Original Title}"
+    },
+    "daily": {
+      "default": "{Series TitleYear} - {Air-Date} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoCodec]}{-Release Group}",
+      "original": "{Original Title}"
+    },
+    "anime": {
+      "default": "{Series TitleYear} - S{season:00}E{episode:00} - {absolute:000} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}[{Mediainfo AudioCodec} { Mediainfo AudioChannels}]{MediaInfo AudioLanguages}{-Release Group}"
+    }
+  }
+}
diff --git a/tests/Recyclarr.TestLibrary/MockFileSystemExtensions.cs b/tests/Recyclarr.TestLibrary/MockFileSystemExtensions.cs
index dd56b832..6c7a432c 100644
--- a/tests/Recyclarr.TestLibrary/MockFileSystemExtensions.cs
+++ b/tests/Recyclarr.TestLibrary/MockFileSystemExtensions.cs
@@ -1,19 +1,9 @@
 using System.IO.Abstractions;
-using System.Reflection;
 
 namespace Recyclarr.TestLibrary;
 
 public static class MockFileSystemExtensions
 {
-    public static void AddFileFromEmbeddedResource(
-        this MockFileSystem fs,
-        IFileInfo path,
-        Assembly resourceAssembly,
-        string embeddedResourcePath)
-    {
-        fs.AddFileFromEmbeddedResource(path.FullName, resourceAssembly, embeddedResourcePath);
-    }
-
     public static void AddFileFromEmbeddedResource(
         this MockFileSystem fs,
         IFileInfo path,
@@ -43,17 +33,13 @@ public static class MockFileSystemExtensions
         fs.AddFileFromEmbeddedResource(path, typeInAssembly, $"{resourceSubPath}.{path.Name}");
     }
 
-    public static void AddSameFileFromEmbeddedResource(
+    public static void AddFilesFromEmbeddedNamespace(
         this MockFileSystem fs,
-        string path,
+        IDirectoryInfo path,
         Type typeInAssembly,
-        string resourceSubPath = "Data")
-    {
-        fs.AddFileFromEmbeddedResource(fs.FileInfo.New(path), typeInAssembly, resourceSubPath);
-    }
-
-    public static IEnumerable<string> LeafDirectories(this MockFileSystem fs)
+        string embeddedResourcePath)
     {
-        return fs.AllDirectories.Where(x => !fs.AllDirectories.Any(y => y.StartsWith(x) && y != x));
+        embeddedResourcePath = $"{typeInAssembly.Namespace}.{embeddedResourcePath.Replace("/", ".")}";
+        fs.AddFilesFromEmbeddedNamespace(path.FullName, typeInAssembly.Assembly, embeddedResourcePath);
     }
 }