diff --git a/.github/workflows/docker-image-cuttingedge.yml b/.github/workflows/docker-image-cuttingedge.yml
index 1346138..b36acd2 100644
--- a/.github/workflows/docker-image-cuttingedge.yml
+++ b/.github/workflows/docker-image-cuttingedge.yml
@@ -36,7 +36,7 @@ jobs:
         uses: docker/build-push-action@v4.1.1
         with:
           context: ./
-          file: ./API/Dockerfile
+          file: ./Dockerfile
           #platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
           platforms: linux/amd64
           pull: true
diff --git a/.github/workflows/docker-image-master.yml b/.github/workflows/docker-image-master.yml
index 35fe424..995c8a2 100644
--- a/.github/workflows/docker-image-master.yml
+++ b/.github/workflows/docker-image-master.yml
@@ -38,7 +38,7 @@ jobs:
         uses: docker/build-push-action@v4.1.1
         with:
           context: ./
-          file: ./API/Dockerfile
+          file: ./Dockerfile
           #platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
           platforms: linux/amd64
           pull: true
diff --git a/API/API.csproj b/API/API.csproj
deleted file mode 100644
index 0622e9c..0000000
--- a/API/API.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-    <PropertyGroup>
-        <OutputType>Exe</OutputType>
-        <TargetFramework>net7.0</TargetFramework>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-        <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
-    </PropertyGroup>
-
-    <ItemGroup>
-      <Content Include="..\.dockerignore">
-        <Link>.dockerignore</Link>
-      </Content>
-    </ItemGroup>
-
-    <ItemGroup>
-      <ProjectReference Include="..\Tranga\Tranga.csproj" />
-    </ItemGroup>
-
-</Project>
diff --git a/API/Program.cs b/API/Program.cs
deleted file mode 100644
index da4f4bf..0000000
--- a/API/Program.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System.Runtime.InteropServices;
-using Logging;
-using Tranga;
-using Tranga.NotificationManagers;
-using Tranga.LibraryManagers;
-
-namespace API;
-
-public static class Program
-{
-    public static void Main(string[] args)
-    {
-        string applicationFolderPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Tranga-API");
-        string downloadFolderPath = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/Manga" : Path.Join(applicationFolderPath, "Manga");
-        string logsFolderPath = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/var/logs/Tranga" : Path.Join(applicationFolderPath, "logs");
-        string logFilePath = Path.Join(logsFolderPath, $"log-{DateTime.Now:dd-M-yyyy-HH-mm-ss}.txt");
-        string settingsFilePath = Path.Join(applicationFolderPath, "settings.json");
-
-        Directory.CreateDirectory(logsFolderPath);
-        Logger logger = new(new[] { Logger.LoggerType.FileLogger, Logger.LoggerType.ConsoleLogger }, Console.Out, Console.Out.Encoding, logFilePath);
-
-        logger.WriteLine("Tranga",value: "\n"+
-            "-------------------------------------------\n"+
-            " Starting Tranga-API\n"+
-            "-------------------------------------------");
-        logger.WriteLine("Tranga", "Loading settings.");
-
-        TrangaSettings settings;
-        if (File.Exists(settingsFilePath))
-            settings = TrangaSettings.LoadSettings(settingsFilePath, logger);
-        else
-            settings = new TrangaSettings(downloadFolderPath, applicationFolderPath, new HashSet<LibraryManager>(), new HashSet<NotificationManager>(), logger);
-
-        Directory.CreateDirectory(settings.workingDirectory);
-        Directory.CreateDirectory(settings.downloadLocation);
-        Directory.CreateDirectory(settings.coverImageCache);
-
-        settings.logger?.WriteLine("Tranga",$"Application-Folder: {settings.workingDirectory}");
-        settings.logger?.WriteLine("Tranga",$"Settings-File-Path: {settings.settingsFilePath}");
-        settings.logger?.WriteLine("Tranga",$"Download-Folder-Path: {settings.downloadLocation}");
-        settings.logger?.WriteLine("Tranga",$"Logfile-Path: {logFilePath}");
-        settings.logger?.WriteLine("Tranga",$"Image-Cache-Path: {settings.coverImageCache}");
-
-        settings.logger?.WriteLine("Tranga", "Loading Taskmanager.");
-        TaskManager taskManager = new (settings);
-        
-        Server server = new (6531, taskManager);
-        foreach(NotificationManager nm in taskManager.settings.notificationManagers)
-            nm.SendNotification("Tranga-API", "Started Tranga-API");
-    }
-}
-
diff --git a/API/Dockerfile b/Dockerfile
similarity index 60%
rename from API/Dockerfile
rename to Dockerfile
index 23e3804..17b6cde 100644
--- a/API/Dockerfile
+++ b/Dockerfile
@@ -2,12 +2,14 @@
 
 FROM mcr.microsoft.com/dotnet/sdk:7.0 as build-env
 WORKDIR /src
-COPY . /src/
-RUN dotnet restore /src/API/API.csproj
+COPY Tranga /src/Tranga
+COPY Logging /src/Logging
+COPY Tranga.sln /src
+RUN dotnet restore /src/Tranga/Tranga.csproj
 RUN dotnet publish -c Release -o /publish
 
 FROM glax/tranga-base:latest as runtime
 WORKDIR /publish
 COPY --from=build-env /publish .
 EXPOSE 6531
-ENTRYPOINT ["dotnet", "/publish/API.dll"]
+ENTRYPOINT ["dotnet", "/publish/Tranga.dll"]
diff --git a/Logging/Logger.cs b/Logging/Logger.cs
index 19baa2a..9ca3d28 100644
--- a/Logging/Logger.cs
+++ b/Logging/Logger.cs
@@ -30,7 +30,7 @@ public class Logger : TextWriter
         {
             _formattedConsoleLogger = new FormattedConsoleLogger(stdOut, encoding);
         }
-        else
+        else if (enabledLoggers.Contains(LoggerType.ConsoleLogger) && stdOut is null)
         {
             _formattedConsoleLogger = null;
             throw new ArgumentException($"stdOut can not be null for LoggerType {LoggerType.ConsoleLogger}");
diff --git a/Tranga-CLI/Tranga-CLI.csproj b/Tranga-CLI/Tranga-CLI.csproj
deleted file mode 100644
index 4d6dbf4..0000000
--- a/Tranga-CLI/Tranga-CLI.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-    <PropertyGroup>
-        <OutputType>Exe</OutputType>
-        <TargetFramework>net7.0</TargetFramework>
-        <RootNamespace>Tranga_CLI</RootNamespace>
-        <ImplicitUsings>enable</ImplicitUsings>
-        <Nullable>enable</Nullable>
-        <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
-    </PropertyGroup>
-
-    <ItemGroup>
-      <ProjectReference Include="..\Tranga\Tranga.csproj" />
-    </ItemGroup>
-
-</Project>
diff --git a/Tranga.sln b/Tranga.sln
index 97a12c6..78a7590 100644
--- a/Tranga.sln
+++ b/Tranga.sln
@@ -2,12 +2,8 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tranga", ".\Tranga\Tranga.csproj", "{545E81B9-D96B-4C8F-A97F-2C02414DE566}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tranga-CLI", "Tranga-CLI\Tranga-CLI.csproj", "{4899E3B2-B259-479A-B43E-042D043E9501}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Logging\Logging.csproj", "{415BE889-BB7D-426F-976F-8D977876A462}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{A8AB1F5F-D174-49DC-AED2-0909B93BA7B6}"
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -18,17 +14,9 @@ Global
 		{545E81B9-D96B-4C8F-A97F-2C02414DE566}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{545E81B9-D96B-4C8F-A97F-2C02414DE566}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{545E81B9-D96B-4C8F-A97F-2C02414DE566}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4899E3B2-B259-479A-B43E-042D043E9501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4899E3B2-B259-479A-B43E-042D043E9501}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4899E3B2-B259-479A-B43E-042D043E9501}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4899E3B2-B259-479A-B43E-042D043E9501}.Release|Any CPU.Build.0 = Release|Any CPU
 		{415BE889-BB7D-426F-976F-8D977876A462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{415BE889-BB7D-426F-976F-8D977876A462}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{415BE889-BB7D-426F-976F-8D977876A462}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{415BE889-BB7D-426F-976F-8D977876A462}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A8AB1F5F-D174-49DC-AED2-0909B93BA7B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A8AB1F5F-D174-49DC-AED2-0909B93BA7B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A8AB1F5F-D174-49DC-AED2-0909B93BA7B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A8AB1F5F-D174-49DC-AED2-0909B93BA7B6}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 EndGlobal
diff --git a/API/RequestHandler.cs b/Tranga/API/RequestHandler.cs
similarity index 99%
rename from API/RequestHandler.cs
rename to Tranga/API/RequestHandler.cs
index 118e3f2..62f7f5c 100644
--- a/API/RequestHandler.cs
+++ b/Tranga/API/RequestHandler.cs
@@ -5,7 +5,7 @@ using Tranga;
 using Tranga.Connectors;
 using Tranga.TrangaTasks;
 
-namespace API;
+namespace Tranga.API;
 
 public class RequestHandler
 {
diff --git a/API/Server.cs b/Tranga/API/Server.cs
similarity index 91%
rename from API/Server.cs
rename to Tranga/API/Server.cs
index c4dd5f3..ae913ed 100644
--- a/API/Server.cs
+++ b/Tranga/API/Server.cs
@@ -6,12 +6,13 @@ using Logging;
 using Newtonsoft.Json;
 using Tranga;
 
-namespace API;
+namespace Tranga.API;
 
 public class Server
 {
     private readonly HttpListener _listener = new ();
     private readonly RequestHandler _requestHandler;
+    private readonly TaskManager _taskManager;
     internal readonly Logger? logger;
 
     private readonly Regex _validUrl =
@@ -19,12 +20,14 @@ public class Server
     public Server(int port, TaskManager taskManager, Logger? logger = null)
     {
         this.logger = logger;
+        this._taskManager = taskManager;
         if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
             this._listener.Prefixes.Add($"http://*:{port}/");
         else
             this._listener.Prefixes.Add($"http://localhost:{port}/");
         this._requestHandler = new RequestHandler(taskManager, this);
-        Listen();
+        Thread listenThread = new Thread(Listen);
+        listenThread.Start();
     }
 
     private void Listen()
@@ -32,7 +35,7 @@ public class Server
         this._listener.Start();
         foreach (string prefix in this._listener.Prefixes)
             this.logger?.WriteLine(this.GetType().ToString(), $"Listening on {prefix}");
-        while (this._listener.IsListening)
+        while (this._listener.IsListening && _taskManager._continueRunning)
         {
             HttpListenerContext context = this._listener.GetContextAsync().Result;
             Task t = new (() =>
diff --git a/Tranga/CommonObjects.cs b/Tranga/CommonObjects.cs
new file mode 100644
index 0000000..531b3fd
--- /dev/null
+++ b/Tranga/CommonObjects.cs
@@ -0,0 +1,124 @@
+using Logging;
+using Newtonsoft.Json;
+using Tranga.LibraryManagers;
+using Tranga.NotificationManagers;
+
+namespace Tranga;
+
+public class CommonObjects
+{
+    public HashSet<LibraryManager> libraryManagers { get; init; }
+    public HashSet<NotificationManager> notificationManagers { get; init; }
+    [JsonIgnore]public Logger? logger { get; set; }
+    [JsonIgnore]private string settingsFilePath { get; init; }
+
+    public CommonObjects(HashSet<LibraryManager>? libraryManagers, HashSet<NotificationManager>? notificationManagers, Logger? logger, string settingsFilePath)
+    {
+        this.libraryManagers = libraryManagers??new();
+        this.notificationManagers = notificationManagers??new();
+        this.logger = logger;
+        this.settingsFilePath = settingsFilePath;
+    }
+
+    public static CommonObjects LoadSettings(string settingsFilePath, Logger? logger)
+    {
+        if (!File.Exists(settingsFilePath))
+            return new CommonObjects(null, null, logger, settingsFilePath);
+
+        string toRead = File.ReadAllText(settingsFilePath);
+        TrangaSettings.SettingsJsonObject settings = JsonConvert.DeserializeObject<TrangaSettings.SettingsJsonObject>(
+            toRead,
+            new JsonSerializerSettings
+            {
+                Converters =
+                {
+                    new NotificationManager.NotificationManagerJsonConverter(),
+                    new LibraryManager.LibraryManagerJsonConverter()
+                }
+            })!;
+        
+        if(settings.co is null)
+            return new CommonObjects(null, null, logger, settingsFilePath);
+        
+        if (logger is not null)
+        {
+            foreach (LibraryManager lm in settings.co.libraryManagers)
+                lm.AddLogger(logger);
+            foreach(NotificationManager nm in settings.co.notificationManagers)
+                nm.AddLogger(logger);
+        }
+
+        return settings.co;
+    }
+    
+    public void ExportSettings()
+    {
+        TrangaSettings.SettingsJsonObject? settings = null;
+        if (File.Exists(settingsFilePath))
+        {
+            bool inUse = true;
+            while (inUse)
+            {
+                try
+                {
+                    using FileStream stream = new (settingsFilePath, FileMode.Open, FileAccess.Read, FileShare.None);
+                    stream.Close();
+                    inUse = false;
+                }
+                catch (IOException)
+                {
+                    inUse = true;
+                    Thread.Sleep(50);
+                }
+            }
+            string toRead = File.ReadAllText(settingsFilePath);
+            settings = JsonConvert.DeserializeObject<TrangaSettings.SettingsJsonObject>(toRead,
+                new JsonSerializerSettings
+                {
+                    Converters =
+                    {
+                        new NotificationManager.NotificationManagerJsonConverter(),
+                        new LibraryManager.LibraryManagerJsonConverter()
+                    }
+                });
+        }
+        settings = new TrangaSettings.SettingsJsonObject(settings?.ts, this);
+        File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(settings));
+    }
+
+    public void UpdateSettings(TrangaSettings.UpdateField field, params string[] values)
+    {
+        switch (field)
+        {
+            case TrangaSettings.UpdateField.Komga:
+                if (values.Length != 2)
+                    return;
+                libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Komga));
+                libraryManagers.Add(new Komga(values[0], values[1], this.logger));
+                break;
+            case TrangaSettings.UpdateField.Kavita:
+                if (values.Length != 3)
+                    return;
+                libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Kavita));
+                libraryManagers.Add(new Kavita(values[0], values[1], values[2], this.logger));
+                break;
+            case TrangaSettings.UpdateField.Gotify:
+                if (values.Length != 2)
+                    return;
+                notificationManagers.RemoveWhere(nm => nm.GetType() == typeof(Gotify));
+                Gotify newGotify = new(values[0], values[1], this.logger);
+                notificationManagers.Add(newGotify);
+                newGotify.SendNotification("Success!", "Gotify was added to Tranga!");
+                break;
+            case TrangaSettings.UpdateField.LunaSea:
+                if(values.Length != 1)
+                    return;
+                notificationManagers.RemoveWhere(nm => nm.GetType() == typeof(LunaSea));
+                LunaSea newLunaSea = new(values[0], this.logger);
+                notificationManagers.Add(newLunaSea);
+                newLunaSea.SendNotification("Success!", "LunaSea was added to Tranga!");
+                break;
+        }
+        ExportSettings();
+    }
+}
\ No newline at end of file
diff --git a/Tranga/Connectors/Connector.cs b/Tranga/Connectors/Connector.cs
index 9233409..391eaa9 100644
--- a/Tranga/Connectors/Connector.cs
+++ b/Tranga/Connectors/Connector.cs
@@ -14,12 +14,14 @@ namespace Tranga.Connectors;
 /// </summary>
 public abstract class Connector
 {
+    protected CommonObjects commonObjects;
     protected TrangaSettings settings { get; }
     internal DownloadClient downloadClient { get; init; } = null!;
     
-    protected Connector(TrangaSettings settings)
+    protected Connector(TrangaSettings settings, CommonObjects commonObjects)
     {
         this.settings = settings;
+        this.commonObjects = commonObjects;
         if (!Directory.Exists(settings.coverImageCache))
             Directory.CreateDirectory(settings.coverImageCache);
     }
@@ -63,11 +65,11 @@ public abstract class Connector
         Chapter[] newChapters = this.GetChapters(publication, language);
         collection.Add(publication);
         NumberFormatInfo decimalPoint = new (){ NumberDecimalSeparator = "." };
-        settings.logger?.WriteLine(this.GetType().ToString(), "Checking for duplicates");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), "Checking for duplicates");
         List<Chapter> newChaptersList = newChapters.Where(nChapter =>
             float.Parse(nChapter.chapterNumber, decimalPoint) > publication.ignoreChaptersBelow &&
             !nChapter.CheckChapterIsDownloaded(settings.downloadLocation)).ToList();
-        settings.logger?.WriteLine(this.GetType().ToString(), $"{newChaptersList.Count} new chapters.");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"{newChaptersList.Count} new chapters.");
         
         return newChaptersList;
     }
@@ -161,19 +163,19 @@ public abstract class Connector
     /// <param name="publication">Publication to retrieve Cover for</param>
     public void CopyCoverFromCacheToDownloadLocation(Publication publication)
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Cloning cover {publication.sortName} -> {publication.internalId}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Cloning cover {publication.sortName} -> {publication.internalId}");
         //Check if Publication already has a Folder and cover
         string publicationFolder = publication.CreatePublicationFolder(settings.downloadLocation);
         DirectoryInfo dirInfo = new (publicationFolder);
         if (dirInfo.EnumerateFiles().Any(info => info.Name.Contains("cover", StringComparison.InvariantCultureIgnoreCase)))
         {
-            settings.logger?.WriteLine(this.GetType().ToString(), $"Cover exists {publication.sortName}");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Cover exists {publication.sortName}");
             return;
         }
 
         string fileInCache = Path.Join(settings.coverImageCache, publication.coverFileNameInCache);
         string newFilePath = Path.Join(publicationFolder, $"cover.{Path.GetFileName(fileInCache).Split('.')[^1]}" );
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Cloning cover {fileInCache} -> {newFilePath}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Cloning cover {fileInCache} -> {newFilePath}");
         File.Copy(fileInCache, newFilePath, true);
         if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
             File.SetUnixFileMode(newFilePath, GroupRead | GroupWrite | OtherRead | OtherWrite | UserRead | UserWrite);
@@ -211,7 +213,7 @@ public abstract class Connector
     {
         if (cancellationToken?.IsCancellationRequested ?? false)
             return HttpStatusCode.RequestTimeout;
-        settings.logger?.WriteLine("Connector", $"Downloading Images for {saveArchiveFilePath}");
+        commonObjects.logger?.WriteLine("Connector", $"Downloading Images for {saveArchiveFilePath}");
         //Check if Publication Directory already exists
         string directoryPath = Path.GetDirectoryName(saveArchiveFilePath)!;
         if (!Directory.Exists(directoryPath))
@@ -229,7 +231,7 @@ public abstract class Connector
         {
             string[] split = imageUrl.Split('.');
             string extension = split[^1];
-            settings.logger?.WriteLine("Connector", $"Downloading Image {chapter + 1:000}/{imageUrls.Length:000} {parentTask.publication.sortName} {parentTask.publication.internalId} Vol.{parentTask.chapter.volumeNumber} Ch.{parentTask.chapter.chapterNumber} {parentTask.progress:P2}");
+            commonObjects.logger?.WriteLine("Connector", $"Downloading Image {chapter + 1:000}/{imageUrls.Length:000} {parentTask.publication.sortName} {parentTask.publication.internalId} Vol.{parentTask.chapter.volumeNumber} Ch.{parentTask.chapter.chapterNumber} {parentTask.progress:P2}");
             HttpStatusCode status = DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapter++}.{extension}"), requestType, referrer);
             if ((int)status < 200 || (int)status >= 300)
                 return status;
@@ -241,7 +243,7 @@ public abstract class Connector
         if(comicInfoPath is not null)
             File.Copy(comicInfoPath, Path.Join(tempFolder, "ComicInfo.xml"));
         
-        settings.logger?.WriteLine("Connector", $"Creating archive {saveArchiveFilePath}");
+        commonObjects.logger?.WriteLine("Connector", $"Creating archive {saveArchiveFilePath}");
         //ZIP-it and ship-it
         ZipFile.CreateFromDirectory(tempFolder, saveArchiveFilePath);
         if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
@@ -263,7 +265,7 @@ public abstract class Connector
         using MemoryStream ms = new();
         coverResult.result.CopyTo(ms);
         File.WriteAllBytes(saveImagePath, ms.ToArray());
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Saving image to {saveImagePath}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Saving image to {saveImagePath}");
         return filename;
     }
 }
\ No newline at end of file
diff --git a/Tranga/Connectors/MangaDex.cs b/Tranga/Connectors/MangaDex.cs
index 4ff9d2c..b63f7a3 100644
--- a/Tranga/Connectors/MangaDex.cs
+++ b/Tranga/Connectors/MangaDex.cs
@@ -18,7 +18,7 @@ public class MangaDex : Connector
         Author,
     }
 
-    public MangaDex(TrangaSettings settings) : base(settings)
+    public MangaDex(TrangaSettings settings, CommonObjects commonObjects) : base(settings, commonObjects)
     {
         name = "MangaDex";
         this.downloadClient = new DownloadClient(new Dictionary<byte, int>()
@@ -28,12 +28,12 @@ public class MangaDex : Connector
             {(byte)RequestType.AtHomeServer, 40},
             {(byte)RequestType.CoverUrl, 250},
             {(byte)RequestType.Author, 250}
-        }, settings.logger);
+        }, commonObjects.logger);
     }
 
     protected override Publication[] GetPublicationsInternal(string publicationTitle = "")
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
         const int limit = 100; //How many values we want returned at once
         int offset = 0; //"Page"
         int total = int.MaxValue; //How many total results are there, is updated on first request
@@ -59,7 +59,7 @@ public class MangaDex : Connector
             //Loop each Manga and extract information from JSON
             foreach (JsonNode? mangeNode in mangaInResult)
             {
-                settings.logger?.WriteLine(this.GetType().ToString(), $"Getting publication data. {++loadedPublicationData}/{total}");
+                commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting publication data. {++loadedPublicationData}/{total}");
                 JsonObject manga = (JsonObject)mangeNode!;
                 JsonObject attributes = manga["attributes"]!.AsObject();
                 
@@ -146,13 +146,13 @@ public class MangaDex : Connector
             }
         }
 
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Done getting publications (title={publicationTitle})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Done getting publications (title={publicationTitle})");
         return publications.ToArray();
     }
 
     public override Chapter[] GetChapters(Publication publication, string language = "")
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
         const int limit = 100; //How many values we want returned at once
         int offset = 0; //"Page"
         int total = int.MaxValue; //How many total results are there, is updated on first request
@@ -203,7 +203,7 @@ public class MangaDex : Connector
         {
             NumberDecimalSeparator = "."
         };
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Done getting {chapters.Count} Chapters for {publication.internalId}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Done getting {chapters.Count} Chapters for {publication.internalId}");
         return chapters.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray();
     }
 
@@ -211,7 +211,7 @@ public class MangaDex : Connector
     {
         if (cancellationToken?.IsCancellationRequested ?? false)
             return HttpStatusCode.RequestTimeout;
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
         //Request URLs for Chapter-Images
         DownloadClient.RequestResult requestResult =
             downloadClient.MakeRequest($"https://api.mangadex.org/at-home/server/{chapter.url}?forcePort443=false'", (byte)RequestType.AtHomeServer);
@@ -238,10 +238,10 @@ public class MangaDex : Connector
 
     private string? GetCoverUrl(string publicationId, string? posterId)
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting CoverUrl for {publicationId}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting CoverUrl for {publicationId}");
         if (posterId is null)
         {
-            settings.logger?.WriteLine(this.GetType().ToString(), $"No posterId, aborting");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), $"No posterId, aborting");
             return null;
         }
         
@@ -257,7 +257,7 @@ public class MangaDex : Connector
         string fileName = result["data"]!["attributes"]!["fileName"]!.GetValue<string>();
 
         string coverUrl = $"https://uploads.mangadex.org/covers/{publicationId}/{fileName}";
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Got Cover-Url for {publicationId} -> {coverUrl}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Got Cover-Url for {publicationId} -> {coverUrl}");
         return coverUrl;
     }
 
@@ -276,7 +276,7 @@ public class MangaDex : Connector
 
             string authorName = result["data"]!["attributes"]!["name"]!.GetValue<string>();
             ret.Add(authorName);
-            settings.logger?.WriteLine(this.GetType().ToString(), $"Got author {authorId} -> {authorName}");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Got author {authorId} -> {authorName}");
         }
         return ret;
     }
diff --git a/Tranga/Connectors/MangaKatana.cs b/Tranga/Connectors/MangaKatana.cs
index 93a0441..e5cec4d 100644
--- a/Tranga/Connectors/MangaKatana.cs
+++ b/Tranga/Connectors/MangaKatana.cs
@@ -10,18 +10,18 @@ public class MangaKatana : Connector
 {
 	public override string name { get; }
 
-	public MangaKatana(TrangaSettings settings) : base(settings)
+	public MangaKatana(TrangaSettings settings, CommonObjects commonObjects) : base(settings, commonObjects)
 	{
 		this.name = "MangaKatana";
 		this.downloadClient = new DownloadClient(new Dictionary<byte, int>()
 		{
 			{1, 60}
-		}, settings.logger);
+		}, commonObjects.logger);
 	}
 
 	protected override Publication[] GetPublicationsInternal(string publicationTitle = "")
 	{
-		settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
+		commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
 		string sanitizedTitle = string.Concat(Regex.Matches(publicationTitle, "[A-z]* *")).ToLower().Replace(' ', '_');
 		string requestUrl = $"https://mangakatana.com/?search={sanitizedTitle}&search_by=book_name";
 		DownloadClient.RequestResult requestResult =
@@ -135,7 +135,7 @@ public class MangaKatana : Connector
 
 	public override Chapter[] GetChapters(Publication publication, string language = "")
 	{
-		settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
+		commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
 		string requestUrl = $"https://mangakatana.com/manga/{publication.publicationId}";
 		// Leaving this in for verification if the page exists
 		DownloadClient.RequestResult requestResult =
@@ -149,7 +149,7 @@ public class MangaKatana : Connector
 			NumberDecimalSeparator = "."
 		};
 		List<Chapter> chapters = ParseChaptersFromHtml(publication, requestUrl);
-		settings.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
+		commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
 		return chapters.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray();
 	}
 
@@ -182,7 +182,7 @@ public class MangaKatana : Connector
 	{
 		if (cancellationToken?.IsCancellationRequested ?? false)
 			return HttpStatusCode.RequestTimeout;
-		settings.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
+		commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
 		string requestUrl = chapter.url;
 		// Leaving this in to check if the page exists
 		DownloadClient.RequestResult requestResult =
diff --git a/Tranga/Connectors/Manganato.cs b/Tranga/Connectors/Manganato.cs
index 19baee7..cfc9791 100644
--- a/Tranga/Connectors/Manganato.cs
+++ b/Tranga/Connectors/Manganato.cs
@@ -10,18 +10,18 @@ public class Manganato : Connector
 {
     public override string name { get; }
     
-    public Manganato(TrangaSettings settings) : base(settings)
+    public Manganato(TrangaSettings settings, CommonObjects commonObjects) : base(settings, commonObjects)
     {
         this.name = "Manganato";
         this.downloadClient = new DownloadClient(new Dictionary<byte, int>()
         {
             {1, 60}
-        }, settings.logger);
+        }, commonObjects.logger);
     }
 
     protected override Publication[] GetPublicationsInternal(string publicationTitle = "")
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
         string sanitizedTitle = string.Join('_', Regex.Matches(publicationTitle, "[A-z]*")).ToLower();
         string requestUrl = $"https://manganato.com/search/story/{sanitizedTitle}";
         DownloadClient.RequestResult requestResult =
@@ -125,7 +125,7 @@ public class Manganato : Connector
 
     public override Chapter[] GetChapters(Publication publication, string language = "")
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Chapters for {publication.sortName} {publication.internalId} (language={language})");
         string requestUrl = $"https://chapmanganato.com/{publication.publicationId}";
         DownloadClient.RequestResult requestResult =
             downloadClient.MakeRequest(requestUrl, 1);
@@ -138,7 +138,7 @@ public class Manganato : Connector
             NumberDecimalSeparator = "."
         };
         List<Chapter> chapters = ParseChaptersFromHtml(publication, requestResult.result);
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
         return chapters.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray();
     }
 
@@ -171,7 +171,7 @@ public class Manganato : Connector
     {
         if (cancellationToken?.IsCancellationRequested ?? false)
             return HttpStatusCode.RequestTimeout;
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
         string requestUrl = chapter.url;
         DownloadClient.RequestResult requestResult =
             downloadClient.MakeRequest(requestUrl, 1);
diff --git a/Tranga/Connectors/Mangasee.cs b/Tranga/Connectors/Mangasee.cs
index c82dd7b..ea9de48 100644
--- a/Tranga/Connectors/Mangasee.cs
+++ b/Tranga/Connectors/Mangasee.cs
@@ -15,13 +15,13 @@ public class Mangasee : Connector
     private IBrowser? _browser;
     private const string ChromiumVersion = "1154303";
 
-    public Mangasee(TrangaSettings settings) : base(settings)
+    public Mangasee(TrangaSettings settings, CommonObjects commonObjects) : base(settings, commonObjects)
     {
         this.name = "Mangasee";
         this.downloadClient = new DownloadClient(new Dictionary<byte, int>()
         {
             { 1, 60 }
-        }, settings.logger);
+        }, commonObjects.logger);
 
         Task d = new Task(DownloadBrowser);
         d.Start();
@@ -34,31 +34,31 @@ public class Mangasee : Connector
             browserFetcher.Remove(rev);
         if (!browserFetcher.LocalRevisions().Contains(ChromiumVersion))
         {
-            settings.logger?.WriteLine(this.GetType().ToString(), "Downloading headless browser");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), "Downloading headless browser");
             DateTime last = DateTime.Now.Subtract(TimeSpan.FromSeconds(5));
             browserFetcher.DownloadProgressChanged += (_, args) =>
             {
                 double currentBytes = Convert.ToDouble(args.BytesReceived) / Convert.ToDouble(args.TotalBytesToReceive);
                 if (args.TotalBytesToReceive == args.BytesReceived)
                 {
-                    settings.logger?.WriteLine(this.GetType().ToString(), "Browser downloaded.");
+                    commonObjects.logger?.WriteLine(this.GetType().ToString(), "Browser downloaded.");
                 }
                 else if (DateTime.Now > last.AddSeconds(5))
                 {
-                    settings.logger?.WriteLine(this.GetType().ToString(), $"Browser download progress: {currentBytes:P2}");
+                    commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Browser download progress: {currentBytes:P2}");
                     last = DateTime.Now;
                 }
 
             };
             if (!browserFetcher.CanDownloadAsync(ChromiumVersion).Result)
             {
-                settings.logger?.WriteLine(this.GetType().ToString(), $"Can't download browser version {ChromiumVersion}");
+                commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Can't download browser version {ChromiumVersion}");
                 return;
             }
             await browserFetcher.DownloadAsync(ChromiumVersion);
         }
         
-        settings.logger?.WriteLine(this.GetType().ToString(), "Starting browser.");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), "Starting browser.");
         this._browser = await Puppeteer.LaunchAsync(new LaunchOptions
         {
             Headless = true,
@@ -73,7 +73,7 @@ public class Mangasee : Connector
 
     protected override Publication[] GetPublicationsInternal(string publicationTitle = "")
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Getting Publications (title={publicationTitle})");
         string requestUrl = $"https://mangasee123.com/_search.php";
         DownloadClient.RequestResult requestResult =
             downloadClient.MakeRequest(requestUrl, 1);
@@ -98,7 +98,7 @@ public class Mangasee : Connector
         queryFiltered = queryFiltered.Where(item => item.Value >= publicationTitle.Split(' ').Length - 1)
             .ToDictionary(item => item.Key, item => item.Value);
         
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Got {queryFiltered.Count} Publications (title={publicationTitle})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Got {queryFiltered.Count} Publications (title={publicationTitle})");
 
         HashSet<Publication> ret = new();
         List<SearchResultItem> orderedFiltered =
@@ -111,7 +111,7 @@ public class Mangasee : Connector
                 downloadClient.MakeRequest($"https://mangasee123.com/manga/{orderedItem.i}", 1);
             if ((int)requestResult.statusCode >= 200 || (int)requestResult.statusCode < 300)
             {
-                settings.logger?.WriteLine(this.GetType().ToString(), $"Retrieving Publication info: {orderedItem.s} {index++}/{orderedFiltered.Count}");
+                commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Retrieving Publication info: {orderedItem.s} {index++}/{orderedFiltered.Count}");
                 ret.Add(ParseSinglePublicationFromHtml(requestResult.result, orderedItem.s, orderedItem.i, orderedItem.a));
             }
         }
@@ -235,7 +235,7 @@ public class Mangasee : Connector
         {
             NumberDecimalSeparator = "."
         };
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Done getting Chapters for {publication.internalId}");
         return ret.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray();
     }
 
@@ -245,13 +245,13 @@ public class Mangasee : Connector
             return HttpStatusCode.RequestTimeout;
         while (this._browser is null && !(cancellationToken?.IsCancellationRequested??false))
         {
-            settings.logger?.WriteLine(this.GetType().ToString(), "Waiting for headless browser to download...");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), "Waiting for headless browser to download...");
             Thread.Sleep(1000);
         }
         if (cancellationToken?.IsCancellationRequested??false)
             return HttpStatusCode.RequestTimeout;
         
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}");
         IPage page = _browser!.NewPageAsync().Result;
         IResponse response = page.GoToAsync(chapter.url).Result;
         if (response.Ok)
diff --git a/Tranga/Migrate.cs b/Tranga/Migrate.cs
deleted file mode 100644
index 02b4988..0000000
--- a/Tranga/Migrate.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Newtonsoft.Json;
-using Tranga.TrangaTasks;
-
-namespace Tranga;
-
-public static class Migrate
-{
-    private static readonly ushort CurrentVersion = 16;
-    public static void Files(TrangaSettings settings)
-    {
-        settings.version ??= 15;
-        switch (settings.version)
-        {
-            case 15:
-                RemoveUpdateLibraryTask(settings);
-                break;
-        }
-
-        settings.version = CurrentVersion;
-        settings.ExportSettings();
-    }
-
-    private static void RemoveUpdateLibraryTask(TrangaSettings settings)
-    {
-        if (!File.Exists(settings.tasksFilePath))
-            return;
-
-        string tasksJsonString = File.ReadAllText(settings.tasksFilePath);
-        HashSet<TrangaTask> tasks = JsonConvert.DeserializeObject<HashSet<TrangaTask>>(tasksJsonString, new JsonSerializerSettings { Converters = { new TrangaTask.TrangaTaskJsonConverter() } })!;
-        tasks.RemoveWhere(t => t.task == TrangaTask.Task.UpdateLibraries);
-        File.WriteAllText(settings.tasksFilePath, JsonConvert.SerializeObject(tasks));
-    }
-}
\ No newline at end of file
diff --git a/Tranga/Migrator.cs b/Tranga/Migrator.cs
new file mode 100644
index 0000000..85c15d7
--- /dev/null
+++ b/Tranga/Migrator.cs
@@ -0,0 +1,97 @@
+using System.Text.Json.Nodes;
+using Logging;
+using Newtonsoft.Json;
+using Tranga.LibraryManagers;
+using Tranga.NotificationManagers;
+using Tranga.TrangaTasks;
+
+namespace Tranga;
+
+public static class Migrator
+{
+    private static readonly ushort CurrentVersion = 17;
+    public static void Migrate(string settingsFilePath, Logger? logger)
+    {
+        if (!File.Exists(settingsFilePath))
+            return;
+        JsonNode settingsNode = JsonNode.Parse(File.ReadAllText(settingsFilePath))!;
+        ushort version = settingsNode["version"]!.GetValue<ushort>();
+        logger?.WriteLine("Migrator", $"Migrating {version} -> {CurrentVersion}");
+        switch (version)
+        {
+            case 15:
+                MoveToCommonObjects(settingsFilePath, logger);
+                TrangaSettings.SettingsJsonObject sjo = JsonConvert.DeserializeObject<TrangaSettings.SettingsJsonObject>(File.ReadAllText(settingsFilePath))!;
+                RemoveUpdateLibraryTask(sjo.ts!, logger);
+                break;
+            case 16:
+                MoveToCommonObjects(settingsFilePath, logger);
+                break;
+        }
+
+        TrangaSettings.SettingsJsonObject sjo2 = JsonConvert.DeserializeObject<TrangaSettings.SettingsJsonObject>(
+            File.ReadAllText(settingsFilePath),
+            new JsonSerializerSettings
+            {
+                Converters =
+                {
+                    new TrangaTask.TrangaTaskJsonConverter(),
+                    new NotificationManager.NotificationManagerJsonConverter(),
+                    new LibraryManager.LibraryManagerJsonConverter()
+                }
+            })!;
+        sjo2.ts!.version = CurrentVersion;
+        sjo2.ts!.ExportSettings();
+    }
+
+    private static void RemoveUpdateLibraryTask(TrangaSettings settings, Logger? logger)
+    {
+        if (!File.Exists(settings.tasksFilePath))
+            return;
+
+        logger?.WriteLine("Migrator", "Removing old/deprecated UpdateLibraryTasks (v16)");
+        string tasksJsonString = File.ReadAllText(settings.tasksFilePath);
+        HashSet<TrangaTask> tasks = JsonConvert.DeserializeObject<HashSet<TrangaTask>>(tasksJsonString,
+            new JsonSerializerSettings { Converters = { new TrangaTask.TrangaTaskJsonConverter() } })!;
+        tasks.RemoveWhere(t => t.task == TrangaTask.Task.UpdateLibraries);
+        File.WriteAllText(settings.tasksFilePath, JsonConvert.SerializeObject(tasks));
+    }
+
+    public static void MoveToCommonObjects(string settingsFilePath, Logger? logger)
+    {
+        if (!File.Exists(settingsFilePath))
+            return;
+
+        logger?.WriteLine("Migrator", "Moving Settings to commonObjects-structure (v17)");
+        JsonNode node = JsonNode.Parse(File.ReadAllText(settingsFilePath))!;
+        TrangaSettings ts = new(
+            node["downloadLocation"]!.GetValue<string>(),
+            node["workingDirectory"]!.GetValue<string>());
+        JsonArray libraryManagers = node["libraryManagers"]!.AsArray();
+        logger?.WriteLine("Migrator", $"\tGot {libraryManagers.Count} libraryManagers.");
+        JsonNode? komgaNode = libraryManagers.FirstOrDefault(lm => lm["libraryType"].GetValue<byte>() == (byte)LibraryManager.LibraryType.Komga);
+        JsonNode? kavitaNode = libraryManagers.FirstOrDefault(lm => lm["libraryType"].GetValue<byte>() == (byte)LibraryManager.LibraryType.Kavita);
+        HashSet<LibraryManager> lms = new();
+        if (komgaNode is not null)
+            lms.Add(new Komga(komgaNode["baseUrl"]!.GetValue<string>(), komgaNode["auth"]!.GetValue<string>(), null));
+        if (kavitaNode is not null)
+            lms.Add(new Kavita(kavitaNode["baseUrl"]!.GetValue<string>(), kavitaNode["auth"]!.GetValue<string>(), null));
+        
+        JsonArray notificationManagers = node["notificationManagers"]!.AsArray();
+        logger?.WriteLine("Migrator", $"\tGot {notificationManagers.Count} notificationManagers.");
+        JsonNode? gotifyNode = notificationManagers.FirstOrDefault(nm =>
+            nm["notificationManagerType"].GetValue<byte>() == (byte)NotificationManager.NotificationManagerType.Gotify);
+        JsonNode? lunaSeaNode = notificationManagers.FirstOrDefault(nm =>
+            nm["notificationManagerType"].GetValue<byte>() == (byte)NotificationManager.NotificationManagerType.LunaSea);
+        HashSet<NotificationManager> nms = new();
+        if (gotifyNode is not null)
+            nms.Add(new Gotify(gotifyNode["endpoint"]!.GetValue<string>(), gotifyNode["appToken"]!.GetValue<string>()));
+        if (lunaSeaNode is not null)
+            nms.Add(new LunaSea(lunaSeaNode["id"]!.GetValue<string>()));
+
+        CommonObjects co = new (lms, nms, null, settingsFilePath);
+
+        TrangaSettings.SettingsJsonObject sjo = new(ts, co);
+        File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(sjo));
+    }
+}
\ No newline at end of file
diff --git a/Tranga/TaskManager.cs b/Tranga/TaskManager.cs
index 11c12d5..04f4afa 100644
--- a/Tranga/TaskManager.cs
+++ b/Tranga/TaskManager.cs
@@ -13,28 +13,29 @@ public class TaskManager
     public HashSet<Publication> collection = new();
     private HashSet<TrangaTask> _allTasks = new();
     private readonly Dictionary<TrangaTask, CancellationTokenSource> _runningTasks = new ();
-    private bool _continueRunning = true;
+    public bool _continueRunning = true;
     private readonly Connector[] _connectors;
     public TrangaSettings settings { get; }
+    public CommonObjects commonObjects { get; init; }
 
-    public TaskManager(TrangaSettings settings)
+    public TaskManager(TrangaSettings settings, Logging.Logger? logger)
     {
-        settings.logger?.WriteLine("Tranga", value: "\n"+
-                                                     @"-----------------------------------------------------------------"+"\n"+
-                                                     @" |¯¯¯¯¯¯|°|¯¯¯¯¯¯\     /¯¯¯¯¯¯| |¯¯¯\|¯¯¯|  /¯¯¯¯¯¯\'   /¯¯¯¯¯¯| "+"\n"+
-                                                     @" |      | |   x  <|'  /   !   | |       '| |   (/¯¯¯\° /   !   | "+ "\n"+
-                                                     @"  ¯|__|¯  |__|\\__\\ /___/¯|_'| |___|\\__|  \\_____/' /___/¯|_'| "+ "\n"+
-                                                     @"-----------------------------------------------------------------");
+        commonObjects = CommonObjects.LoadSettings(settings.settingsFilePath, logger);
+        commonObjects.logger?.WriteLine("Tranga", value: "\n"+
+                                                         @"-----------------------------------------------------------------"+"\n"+
+                                                         @" |¯¯¯¯¯¯|°|¯¯¯¯¯¯\     /¯¯¯¯¯¯| |¯¯¯\|¯¯¯|  /¯¯¯¯¯¯\'   /¯¯¯¯¯¯| "+"\n"+
+                                                         @" |      | |   x  <|'  /   !   | |       '| |   (/¯¯¯\° /   !   | "+ "\n"+
+                                                         @"  ¯|__|¯  |__|\\__\\ /___/¯|_'| |___|\\__|  \\_____/' /___/¯|_'| "+ "\n"+
+                                                         @"-----------------------------------------------------------------");
         this._connectors = new Connector[]
         {
-            new MangaDex(settings),
-            new Manganato(settings),
-            new Mangasee(settings),
-            new MangaKatana(settings)
+            new MangaDex(settings, commonObjects),
+            new Manganato(settings, commonObjects),
+            new Mangasee(settings, commonObjects),
+            new MangaKatana(settings, commonObjects)
         };
         
         this.settings = settings;
-        Migrate.Files(settings);
         ImportData();
         ExportDataAndSettings();
         Thread taskChecker = new(TaskCheckerThread);
@@ -47,7 +48,7 @@ public class TaskManager
     /// </summary>
     private void TaskCheckerThread()
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), "Starting TaskCheckerThread.");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), "Starting TaskCheckerThread.");
         int waitingTasksCount = _allTasks.Count(task => task.state is TrangaTask.ExecutionState.Waiting);
         while (_continueRunning)
         {
@@ -146,7 +147,7 @@ public class TaskManager
         {
             case TrangaTask.Task.UpdateLibraries:
                 //Only one UpdateKomgaLibrary Task
-                settings.logger?.WriteLine(this.GetType().ToString(), $"Replacing old {newTask.task}-Task.");
+                commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Replacing old {newTask.task}-Task.");
                 if (GetTasksMatching(newTask).FirstOrDefault() is { } exists)
                     _allTasks.Remove(exists);
                 _allTasks.Add(newTask);
@@ -155,19 +156,19 @@ public class TaskManager
             default:
                 if (!GetTasksMatching(newTask).Any())
                 {
-                    settings.logger?.WriteLine(this.GetType().ToString(), $"Adding new Task {newTask}");
+                    commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Adding new Task {newTask}");
                     _allTasks.Add(newTask);
                     ExportDataAndSettings();
                 }
                 else
-                    settings.logger?.WriteLine(this.GetType().ToString(), $"Task already exists {newTask}");
+                    commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Task already exists {newTask}");
                 break;
         }
     }
 
     public void DeleteTask(TrangaTask removeTask)
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Removing Task {removeTask}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Removing Task {removeTask}");
         if(_allTasks.Contains(removeTask))
             _allTasks.Remove(removeTask);
         removeTask.parentTask?.RemoveChildTask(removeTask);
@@ -319,7 +320,7 @@ public class TaskManager
     /// <param name="force">If force is true, tasks are aborted.</param>
     public void Shutdown(bool force = false)
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Shutting down (forced={force})");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Shutting down (forced={force})");
         _continueRunning = false;
         ExportDataAndSettings();
         
@@ -329,16 +330,16 @@ public class TaskManager
         //Wait for tasks to finish
         while(_allTasks.Any(task => task.state is TrangaTask.ExecutionState.Running or TrangaTask.ExecutionState.Enqueued))
             Thread.Sleep(10);
-        settings.logger?.WriteLine(this.GetType().ToString(), "Tasks finished. Bye!");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), "Tasks finished. Bye!");
         Environment.Exit(0);
     }
 
     private void ImportData()
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), "Importing Data");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), "Importing Data");
         if (File.Exists(settings.tasksFilePath))
         {
-            settings.logger?.WriteLine(this.GetType().ToString(), $"Importing tasks from {settings.tasksFilePath}");
+            commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Importing tasks from {settings.tasksFilePath}");
             string buffer = File.ReadAllText(settings.tasksFilePath);
             this._allTasks = JsonConvert.DeserializeObject<HashSet<TrangaTask>>(buffer, new JsonSerializerSettings() { Converters = { new TrangaTask.TrangaTaskJsonConverter() } })!;
         }
@@ -359,10 +360,10 @@ public class TaskManager
     /// </summary>
     private void ExportDataAndSettings()
     {
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Exporting settings to {settings.settingsFilePath}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Exporting settings to {settings.settingsFilePath}");
         settings.ExportSettings();
         
-        settings.logger?.WriteLine(this.GetType().ToString(), $"Exporting tasks to {settings.tasksFilePath}");
+        commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Exporting tasks to {settings.tasksFilePath}");
         while(IsFileInUse(settings.tasksFilePath))
             Thread.Sleep(50);
         File.WriteAllText(settings.tasksFilePath, JsonConvert.SerializeObject(this._allTasks));
diff --git a/Tranga-CLI/Tranga_Cli.cs b/Tranga/Tranga.cs
similarity index 70%
rename from Tranga-CLI/Tranga_Cli.cs
rename to Tranga/Tranga.cs
index a131b5e..63a51ae 100644
--- a/Tranga-CLI/Tranga_Cli.cs
+++ b/Tranga/Tranga.cs
@@ -1,139 +1,70 @@
 using System.Globalization;
+using System.Runtime.InteropServices;
 using Logging;
-using Tranga;
+using Tranga.API;
 using Tranga.Connectors;
-using Tranga.LibraryManagers;
 using Tranga.NotificationManagers;
 using Tranga.TrangaTasks;
 
-namespace Tranga_CLI;
+namespace Tranga;
 
-/*
- * This is written with pure hatred for readability.
- * At some point do this properly.
- * Read at own risk.
- */
-
-public static class Tranga_Cli
+public static class Tranga
 {
     public static void Main(string[] args)
     {
-        string applicationFolderPath =  Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Tranga");
-        string logsFolderPath = Path.Join(applicationFolderPath, "logs");
+        bool isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+        string applicationFolderPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Tranga-API"); 
+        
+        string downloadFolderPath = isLinux ? "/Manga" : Path.Join(applicationFolderPath, "Manga");
+        string logsFolderPath = isLinux ? "/var/log/Tranga" : Path.Join(applicationFolderPath, "log");
         string logFilePath = Path.Join(logsFolderPath, $"log-{DateTime.Now:dd-M-yyyy-HH-mm-ss}.txt");
         string settingsFilePath = Path.Join(applicationFolderPath, "settings.json");
-
-        Directory.CreateDirectory(applicationFolderPath);
+        
+        
         Directory.CreateDirectory(logsFolderPath);
+        Logger logger = isLinux
+            ? new Logger(new[] { Logger.LoggerType.FileLogger, Logger.LoggerType.ConsoleLogger }, Console.Out, Console.Out.Encoding, logFilePath)
+            : new Logger(new[] { Logger.LoggerType.FileLogger }, Console.Out, Console.Out.Encoding, logFilePath);
         
-        Console.WriteLine($"Logfile-Path: {logFilePath}");
-        Console.WriteLine($"Settings-File-Path: {settingsFilePath}");
+        logger.WriteLine("Tranga",value: "\n"+
+                                         "-------------------------------------------\n"+
+                                         " Starting Tranga-API\n"+
+                                         "-------------------------------------------");
+        logger.WriteLine("Tranga", "Migrating...");
+        Migrator.Migrate(settingsFilePath, logger);
 
-        Logger logger = new(new[] { Logger.LoggerType.FileLogger }, null, Console.Out.Encoding, logFilePath);
-        
-        logger.WriteLine("Tranga_CLI", "Loading Taskmanager.");
-        TrangaSettings settings = File.Exists(settingsFilePath) ? TrangaSettings.LoadSettings(settingsFilePath, logger) : new TrangaSettings(Directory.GetCurrentDirectory(), applicationFolderPath, new HashSet<LibraryManager>(), new HashSet<NotificationManager>(), logger);
-
-            
-        settings.logger?.WriteLine("Tranga_CLI", "User Input");
-        Console.WriteLine($"Output folder path [{settings.downloadLocation}]:");
-        string? tmpPath = Console.ReadLine();
-        while(tmpPath is null)
-            tmpPath = Console.ReadLine();
-        if (tmpPath.Length > 0)
-            settings.UpdateSettings(TrangaSettings.UpdateField.DownloadLocation, tmpPath);
-
-        Console.WriteLine($"Komga BaseURL [{settings.libraryManagers.FirstOrDefault(lm => lm.GetType() == typeof(Komga))?.baseUrl}]:");
-        string? tmpUrlKomga = Console.ReadLine();
-        while (tmpUrlKomga is null)
-            tmpUrlKomga = Console.ReadLine();
-        if (tmpUrlKomga.Length > 0)
+        TrangaSettings settings;
+        if (File.Exists(settingsFilePath))
         {
-            Console.WriteLine("Username:");
-            string? tmpKomgaUser = Console.ReadLine();
-            while (tmpKomgaUser is null || tmpKomgaUser.Length < 1)
-                tmpKomgaUser = Console.ReadLine();
-            
-            Console.WriteLine("Password:");
-            string tmpKomgaPass = string.Empty;
-            ConsoleKey key;
-            do
-            {
-                var keyInfo = Console.ReadKey(intercept: true);
-                key = keyInfo.Key;
+            logger.WriteLine("Tranga", $"Loading settings {settingsFilePath}");
+            settings = TrangaSettings.LoadSettings(settingsFilePath);
+        }else
+            settings = new TrangaSettings(downloadFolderPath, applicationFolderPath);
 
-                if (key == ConsoleKey.Backspace && tmpKomgaPass.Length > 0)
-                {
-                    Console.Write("\b \b");
-                    tmpKomgaPass = tmpKomgaPass[0..^1];
-                }
-                else if (!char.IsControl(keyInfo.KeyChar))
-                {
-                    Console.Write("*");
-                    tmpKomgaPass += keyInfo.KeyChar;
-                }
-            } while (key != ConsoleKey.Enter);
+        Directory.CreateDirectory(settings.workingDirectory);
+        Directory.CreateDirectory(settings.downloadLocation);
+        Directory.CreateDirectory(settings.coverImageCache);
 
-            settings.UpdateSettings(TrangaSettings.UpdateField.Komga, tmpUrlKomga, tmpKomgaUser, tmpKomgaPass);
-        }
+        logger.WriteLine("Tranga", $"Is Linux: {isLinux}");
+        logger.WriteLine("Tranga",$"Application-Folder: {settings.workingDirectory}");
+        logger.WriteLine("Tranga",$"Settings-File-Path: {settings.settingsFilePath}");
+        logger.WriteLine("Tranga",$"Download-Folder-Path: {settings.downloadLocation}");
+        logger.WriteLine("Tranga",$"Logfile-Path: {logFilePath}");
+        logger.WriteLine("Tranga",$"Image-Cache-Path: {settings.coverImageCache}");
+
+        logger.WriteLine("Tranga", "Loading Taskmanager.");
+        TaskManager taskManager = new (settings, logger);
         
-        Console.WriteLine($"Kavita BaseURL [{settings.libraryManagers.FirstOrDefault(lm => lm.GetType() == typeof(Kavita))?.baseUrl}]:");
-        string? tmpUrlKavita = Console.ReadLine();
-        while (tmpUrlKavita is null)
-            tmpUrlKavita = Console.ReadLine();
-        if (tmpUrlKavita.Length > 0)
-        {
-            Console.WriteLine("Username:");
-            string? tmpKavitaUser = Console.ReadLine();
-            while (tmpKavitaUser is null || tmpKavitaUser.Length < 1)
-                tmpKavitaUser = Console.ReadLine();
-            
-            Console.WriteLine("Password:");
-            string tmpKavitaPass = string.Empty;
-            ConsoleKey key;
-            do
-            {
-                var keyInfo = Console.ReadKey(intercept: true);
-                key = keyInfo.Key;
-
-                if (key == ConsoleKey.Backspace && tmpKavitaPass.Length > 0)
-                {
-                    Console.Write("\b \b");
-                    tmpKavitaPass = tmpKavitaPass[0..^1];
-                }
-                else if (!char.IsControl(keyInfo.KeyChar))
-                {
-                    Console.Write("*");
-                    tmpKavitaPass += keyInfo.KeyChar;
-                }
-            } while (key != ConsoleKey.Enter);
-
-            settings.UpdateSettings(TrangaSettings.UpdateField.Kavita,  tmpUrlKavita, tmpKavitaUser, tmpKavitaPass);
-        }
+        Server _ = new (6531, taskManager);
+        foreach(NotificationManager nm in taskManager.commonObjects.notificationManagers)
+            nm.SendNotification("Tranga-API", "Started Tranga-API");
         
-        Console.WriteLine($"Gotify BaseURL [{((Gotify?)settings.notificationManagers.FirstOrDefault(lm => lm.GetType() == typeof(Gotify)))?.endpoint}]:");
-        string? tmpGotifyUrl = Console.ReadLine();
-        while (tmpGotifyUrl is null)
-            tmpGotifyUrl = Console.ReadLine();
-        if (tmpGotifyUrl.Length > 0)
-        {
-            Console.WriteLine("AppToken:");
-            string? tmpGotifyAppToken = Console.ReadLine();
-            while (tmpGotifyAppToken is null || tmpGotifyAppToken.Length < 1)
-                tmpGotifyAppToken = Console.ReadLine();
-
-            settings.UpdateSettings(TrangaSettings.UpdateField.Gotify,  tmpGotifyUrl, tmpGotifyAppToken);
-        }
-        
-        logger.WriteLine("Tranga_CLI", "Loaded.");
-        foreach(NotificationManager nm in settings.notificationManagers)
-            nm.SendNotification("Tranga", "Loaded.");
-        TaskMode(settings, logger);
+        if(!isLinux)
+            TaskMode(taskManager, logger);
     }
-
-    private static void TaskMode(TrangaSettings settings, Logger logger)
+    
+    private static void TaskMode(TaskManager taskManager, Logger logger)
     {
-        TaskManager taskManager = new (settings);
         ConsoleKey selection = ConsoleKey.EraseEndOfFile;
         PrintMenu(taskManager, taskManager.settings.downloadLocation);
         while (selection != ConsoleKey.Q)
@@ -160,22 +91,22 @@ public static class Tranga_Cli
                         Console.ReadKey();
                         break;
                     case ConsoleKey.C:
-                        CreateTask(taskManager, logger);
+                        CreateTask(taskManager);
                         Console.WriteLine("Press any key.");
                         Console.ReadKey();
                         break;
                     case ConsoleKey.D:
-                        DeleteTask(taskManager, logger);
+                        DeleteTask(taskManager);
                         Console.WriteLine("Press any key.");
                         Console.ReadKey();
                         break;
                     case ConsoleKey.E:
-                        ExecuteTaskNow(taskManager, logger);
+                        ExecuteTaskNow(taskManager);
                         Console.WriteLine("Press any key.");
                         Console.ReadKey();
                         break;
                     case ConsoleKey.S:
-                        SearchTasks(taskManager, logger);
+                        SearchTasks(taskManager);
                         Console.WriteLine("Press any key.");
                         Console.ReadKey();
                         break;
@@ -241,7 +172,7 @@ public static class Tranga_Cli
             // ReSharper disable once RedundantArgumentDefaultValue Better readability
             taskManager.Shutdown(false);
     }
-
+    
     private static void PrintMenu(TaskManager taskManager, string folderPath)
     {
         int taskCount = taskManager.GetAllTasks().Length;
@@ -258,10 +189,10 @@ public static class Tranga_Cli
         Console.WriteLine($"{"M: New Download Manga Task",-30}{"", -30}{"", -30}");
         Console.WriteLine($"{"",-30}{"F: Show Log",-30}{"Q: Exit",-30}");
     }
-
-    private static void PrintTasks(TrangaTask[] tasks, Logger logger)
+    
+    private static void PrintTasks(TrangaTask[] tasks, Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Printing Tasks");
+        logger?.WriteLine("Tranga_CLI", "Printing Tasks");
         int taskCount = tasks.Length;
         int taskRunningCount = tasks.Count(task => task.state == TrangaTask.ExecutionState.Running);
         int taskEnqueuedCount = tasks.Count(task => task.state == TrangaTask.ExecutionState.Enqueued);
@@ -280,19 +211,19 @@ public static class Tranga_Cli
             
     }
 
-    private static TrangaTask[] SelectTasks(TrangaTask[] tasks, Logger logger)
+    private static TrangaTask[] SelectTasks(TrangaTask[] tasks, Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select task");
+        logger?.WriteLine("Tranga_CLI", "Menu: Select task");
         if (tasks.Length < 1)
         {
             Console.Clear();
             Console.WriteLine("There are no available Tasks.");
-            logger.WriteLine("Tranga_CLI", "No available Tasks.");
+            logger?.WriteLine("Tranga_CLI", "No available Tasks.");
             return Array.Empty<TrangaTask>();
         }
         PrintTasks(tasks, logger);
         
-        logger.WriteLine("Tranga_CLI", "Selecting Task to Remove (from queue)");
+        logger?.WriteLine("Tranga_CLI", "Selecting Task to Remove (from queue)");
         Console.WriteLine("Enter q to abort");
         Console.WriteLine($"Select Task(s) (0-{tasks.Length - 1}):");
 
@@ -304,7 +235,7 @@ public static class Tranga_Cli
         {
             Console.Clear();
             Console.WriteLine("aborted.");
-            logger.WriteLine("Tranga_CLI", "aborted");
+            logger?.WriteLine("Tranga_CLI", "aborted");
             return Array.Empty<TrangaTask>();
         }
 
@@ -330,7 +261,7 @@ public static class Tranga_Cli
         if (connector is null)
             return;
                     
-        Publication? publication = SelectPublication(taskManager, connector, logger);
+        Publication? publication = SelectPublication(taskManager, connector);
         if (publication is null)
             return;
         
@@ -386,10 +317,10 @@ public static class Tranga_Cli
         }
     }
 
-    private static void CreateTask(TaskManager taskManager, Logger logger)
+    private static void CreateTask(TaskManager taskManager)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Creating Task");
-        TrangaTask.Task? tmpTask = SelectTaskType(logger);
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Menu: Creating Task");
+        TrangaTask.Task? tmpTask = SelectTaskType(taskManager.commonObjects.logger);
         if (tmpTask is null)
             return;
         TrangaTask.Task task = (TrangaTask.Task)tmpTask;
@@ -397,7 +328,7 @@ public static class Tranga_Cli
         Connector? connector = null;
         if (task != TrangaTask.Task.UpdateLibraries)
         {
-            connector = SelectConnector(taskManager.GetAvailableConnectors().Values.ToArray(), logger);
+            connector = SelectConnector(taskManager.GetAvailableConnectors().Values.ToArray(), taskManager.commonObjects.logger);
             if (connector is null)
                 return;
         }
@@ -405,22 +336,22 @@ public static class Tranga_Cli
         Publication? publication = null;
         if (task != TrangaTask.Task.UpdateLibraries)
         {
-            publication = SelectPublication(taskManager, connector!, logger);
+            publication = SelectPublication(taskManager, connector!);
             if (publication is null)
                 return;
         }
 
         if (task is TrangaTask.Task.MonitorPublication)
         {
-            TimeSpan reoccurrence = SelectReoccurrence(logger);
-            logger.WriteLine("Tranga_CLI", "Sending Task to TaskManager");
+            TimeSpan reoccurrence = SelectReoccurrence(taskManager.commonObjects.logger);
+            taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Sending Task to TaskManager");
 
             TrangaTask newTask = new MonitorPublicationTask(connector!.name, (Publication)publication!, reoccurrence, "en");
             taskManager.AddTask(newTask);
             Console.WriteLine(newTask);
         }else if (task is TrangaTask.Task.DownloadChapter)
         {
-            foreach (Chapter chapter in SelectChapters(connector!, (Publication)publication!, logger))
+            foreach (Chapter chapter in SelectChapters(connector!, (Publication)publication!, taskManager.commonObjects.logger))
             {
                 TrangaTask newTask = new DownloadChapterTask(connector!.name, (Publication)publication, chapter, "en");
                 taskManager.AddTask(newTask);
@@ -429,31 +360,31 @@ public static class Tranga_Cli
         }
     }
 
-    private static void ExecuteTaskNow(TaskManager taskManager, Logger logger)
+    private static void ExecuteTaskNow(TaskManager taskManager)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Executing Task");
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Menu: Executing Task");
         TrangaTask[] tasks = taskManager.GetAllTasks().Where(nTask => nTask.state is not TrangaTask.ExecutionState.Running).ToArray();
         
-        TrangaTask[] selectedTasks = SelectTasks(tasks, logger);
-        logger.WriteLine("Tranga_CLI", $"Sending {selectedTasks.Length} Tasks to TaskManager");
+        TrangaTask[] selectedTasks = SelectTasks(tasks, taskManager.commonObjects.logger);
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", $"Sending {selectedTasks.Length} Tasks to TaskManager");
         foreach(TrangaTask task in selectedTasks)
             taskManager.ExecuteTaskNow(task);
     }
 
-    private static void DeleteTask(TaskManager taskManager, Logger logger)
+    private static void DeleteTask(TaskManager taskManager)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Delete Task");
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Menu: Delete Task");
         TrangaTask[] tasks = taskManager.GetAllTasks();
         
-        TrangaTask[] selectedTasks = SelectTasks(tasks, logger);
-        logger.WriteLine("Tranga_CLI", $"Sending {selectedTasks.Length} Tasks to TaskManager");
+        TrangaTask[] selectedTasks = SelectTasks(tasks, taskManager.commonObjects.logger);
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", $"Sending {selectedTasks.Length} Tasks to TaskManager");
         foreach(TrangaTask task in selectedTasks)
             taskManager.DeleteTask(task);
     }
 
-    private static TrangaTask.Task? SelectTaskType(Logger logger)
+    private static TrangaTask.Task? SelectTaskType(Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select TaskType");
+        logger?.WriteLine("Tranga_CLI", "Menu: Select TaskType");
         Console.Clear();
         string[] taskNames = Enum.GetNames<TrangaTask.Task>();
         
@@ -473,7 +404,7 @@ public static class Tranga_Cli
         {
             Console.Clear();
             Console.WriteLine("aborted.");
-            logger.WriteLine("Tranga_CLI", "aborted.");
+            logger?.WriteLine("Tranga_CLI", "aborted.");
             return null;
         }
         
@@ -486,22 +417,22 @@ public static class Tranga_Cli
         catch (Exception e)
         {
             Console.WriteLine($"Exception: {e.Message}");
-            logger.WriteLine("Tranga_CLI", e.Message);
+            logger?.WriteLine("Tranga_CLI", e.Message);
         }
 
         return null;
     }
 
-    private static TimeSpan SelectReoccurrence(Logger logger)
+    private static TimeSpan SelectReoccurrence(Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select Reoccurrence");
+        logger?.WriteLine("Tranga_CLI", "Menu: Select Reoccurrence");
         Console.WriteLine("Select reoccurrence Timer (Format hh:mm:ss):");
         return TimeSpan.Parse(Console.ReadLine()!, new CultureInfo("en-US"));
     }
 
-    private static Chapter[] SelectChapters(Connector connector, Publication publication, Logger logger)
+    private static Chapter[] SelectChapters(Connector connector, Publication publication, Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select Chapters");
+        logger?.WriteLine("Tranga_CLI", "Menu: Select Chapters");
         Chapter[] availableChapters = connector.GetChapters(publication, "en");
         int cIndex = 0;
         Console.WriteLine("Chapters:");
@@ -540,9 +471,9 @@ public static class Tranga_Cli
         return connector.SelectChapters(publication, selectedChapters);
     }
 
-    private static Connector? SelectConnector(Connector[] connectors, Logger logger)
+    private static Connector? SelectConnector(Connector[] connectors, Logger? logger)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select Connector");
+        logger?.WriteLine("Tranga_CLI", "Menu: Select Connector");
         Console.Clear();
         
         int cIndex = 0;
@@ -561,7 +492,7 @@ public static class Tranga_Cli
         {
             Console.Clear();
             Console.WriteLine("aborted.");
-            logger.WriteLine("Tranga_CLI", "aborted.");
+            logger?.WriteLine("Tranga_CLI", "aborted.");
             return null;
         }
         
@@ -573,15 +504,15 @@ public static class Tranga_Cli
         catch (Exception e)
         {
             Console.WriteLine($"Exception: {e.Message}");
-            logger.WriteLine("Tranga_CLI", e.Message);
+            logger?.WriteLine("Tranga_CLI", e.Message);
         }
 
         return null;
     }
 
-    private static Publication? SelectPublication(TaskManager taskManager, Connector connector, Logger logger)
+    private static Publication? SelectPublication(TaskManager taskManager, Connector connector)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Select Publication");
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Menu: Select Publication");
         
         Console.Clear();
         Console.WriteLine($"Connector: {connector.name}");
@@ -592,7 +523,7 @@ public static class Tranga_Cli
 
         if (publications.Length < 1)
         {
-            logger.WriteLine("Tranga_CLI", "No publications returned");
+            taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "No publications returned");
             Console.WriteLine($"No publications for query '{query}' returned;");
             return null;
         }
@@ -613,7 +544,7 @@ public static class Tranga_Cli
         {
             Console.Clear();
             Console.WriteLine("aborted.");
-            logger.WriteLine("Tranga_CLI", "aborted.");
+            taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "aborted.");
             return null;
         }
         
@@ -625,21 +556,21 @@ public static class Tranga_Cli
         catch (Exception e)
         {
             Console.WriteLine($"Exception: {e.Message}");
-            logger.WriteLine("Tranga_CLI", e.Message);
+            taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", e.Message);
         }
 
         return null;
     }
 
-    private static void SearchTasks(TaskManager taskManager, Logger logger)
+    private static void SearchTasks(TaskManager taskManager)
     {
-        logger.WriteLine("Tranga_CLI", "Menu: Search task");
+        taskManager.commonObjects.logger?.WriteLine("Tranga_CLI", "Menu: Search task");
         Console.Clear();
         Console.WriteLine("Enter search query:");
         string? query = Console.ReadLine();
         while (query is null || query.Length < 4)
             query = Console.ReadLine();
         PrintTasks(taskManager.GetAllTasks().Where(qTask =>
-            qTask.ToString().ToLower().Contains(query, StringComparison.OrdinalIgnoreCase)).ToArray(), logger);
+            qTask.ToString().ToLower().Contains(query, StringComparison.OrdinalIgnoreCase)).ToArray(), taskManager.commonObjects.logger);
     }
 }
\ No newline at end of file
diff --git a/Tranga/Tranga.csproj b/Tranga/Tranga.csproj
index a2edb49..2e4242b 100644
--- a/Tranga/Tranga.csproj
+++ b/Tranga/Tranga.csproj
@@ -4,6 +4,7 @@
         <TargetFramework>net7.0</TargetFramework>
         <ImplicitUsings>enable</ImplicitUsings>
         <Nullable>enable</Nullable>
+        <OutputType>Exe</OutputType>
     </PropertyGroup>
 
     <ItemGroup>
@@ -16,4 +17,11 @@
       <ProjectReference Include="..\Logging\Logging.csproj" />
     </ItemGroup>
 
+    <ItemGroup>
+      <Content Include="..\.dockerignore">
+        <Link>.dockerignore</Link>
+        <DependentUpon>Dockerfile</DependentUpon>
+      </Content>
+    </ItemGroup>
+
 </Project>
diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs
index fdeddfe..6173ac2 100644
--- a/Tranga/TrangaSettings.cs
+++ b/Tranga/TrangaSettings.cs
@@ -1,4 +1,5 @@
-using Logging;
+using System.Text.Json.Nodes;
+using Logging;
 using Newtonsoft.Json;
 using Tranga.LibraryManagers;
 using Tranga.NotificationManagers;
@@ -12,45 +13,31 @@ public class TrangaSettings
     [JsonIgnore] public string settingsFilePath => Path.Join(workingDirectory, "settings.json");
     [JsonIgnore] public string tasksFilePath => Path.Join(workingDirectory, "tasks.json");
     [JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
-    public HashSet<LibraryManager> libraryManagers { get; }
-    public HashSet<NotificationManager> notificationManagers { get; }
     public ushort? version { get; set; }
-    [JsonIgnore] public Logger? logger { get; init; }
 
-    public TrangaSettings(string downloadLocation, string workingDirectory, HashSet<LibraryManager>? libraryManagers,
-        HashSet<NotificationManager>? notificationManagers, Logger? logger)
+    public TrangaSettings(string downloadLocation, string workingDirectory)
     {
         if (downloadLocation.Length < 1 || workingDirectory.Length < 1)
             throw new ArgumentException("Download-location and working-directory paths can not be empty!");
         this.workingDirectory = workingDirectory;
         this.downloadLocation = downloadLocation;
-        this.libraryManagers = libraryManagers??new();
-        this.notificationManagers = notificationManagers??new();
-        this.logger = logger;
     }
 
-    public static TrangaSettings LoadSettings(string importFilePath, Logger? logger)
+    public static TrangaSettings LoadSettings(string importFilePath)
     {
         if (!File.Exists(importFilePath))
-            return new TrangaSettings(Path.Join(Directory.GetCurrentDirectory(), "Downloads"),
-                Directory.GetCurrentDirectory(), new HashSet<LibraryManager>(), new HashSet<NotificationManager>(), logger);
+            return new TrangaSettings(Path.Join(Directory.GetCurrentDirectory(), "Downloads"), Directory.GetCurrentDirectory());
 
         string toRead = File.ReadAllText(importFilePath);
-        TrangaSettings settings = JsonConvert.DeserializeObject<TrangaSettings>(toRead,
+        SettingsJsonObject settings = JsonConvert.DeserializeObject<SettingsJsonObject>(toRead,
             new JsonSerializerSettings { Converters = { new NotificationManager.NotificationManagerJsonConverter(), new LibraryManager.LibraryManagerJsonConverter() } })!;
-        if (logger is not null)
-        {
-            foreach (LibraryManager lm in settings.libraryManagers)
-                lm.AddLogger(logger);
-            foreach(NotificationManager nm in settings.notificationManagers)
-                nm.AddLogger(logger);
-        }
+        return settings.ts ?? new TrangaSettings(Path.Join(Directory.GetCurrentDirectory(), "Downloads"), Directory.GetCurrentDirectory());
 
-        return settings;
     }
 
     public void ExportSettings()
     {
+        SettingsJsonObject? settings = null;
         if (File.Exists(settingsFilePath))
         {
             bool inUse = true;
@@ -68,8 +55,19 @@ public class TrangaSettings
                     Thread.Sleep(50);
                 }
             }
+            string toRead = File.ReadAllText(settingsFilePath);
+            settings = JsonConvert.DeserializeObject<SettingsJsonObject>(toRead,
+                new JsonSerializerSettings
+                {
+                    Converters =
+                    {
+                        new NotificationManager.NotificationManagerJsonConverter(),
+                        new LibraryManager.LibraryManagerJsonConverter()
+                    }
+                });
         }
-        File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(this));
+        settings = new SettingsJsonObject(this, settings?.co);
+        File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(settings));
     }
 
     public void UpdateSettings(UpdateField field, params string[] values) 
@@ -81,37 +79,21 @@ public class TrangaSettings
                     return;
                 this.downloadLocation = values[0];
                 break;
-            case UpdateField.Komga:
-                if (values.Length != 2)
-                    return;
-                libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Komga));
-                libraryManagers.Add(new Komga(values[0], values[1], this.logger));
-                break;
-            case UpdateField.Kavita:
-                if (values.Length != 3)
-                    return;
-                libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Kavita));
-                libraryManagers.Add(new Kavita(values[0], values[1], values[2], this.logger));
-                break;
-            case UpdateField.Gotify:
-                if (values.Length != 2)
-                    return;
-                notificationManagers.RemoveWhere(nm => nm.GetType() == typeof(Gotify));
-                Gotify newGotify = new(values[0], values[1], this.logger);
-                notificationManagers.Add(newGotify);
-                newGotify.SendNotification("Success!", "Gotify was added to Tranga!");
-                break;
-            case UpdateField.LunaSea:
-                if(values.Length != 1)
-                    return;
-                notificationManagers.RemoveWhere(nm => nm.GetType() == typeof(LunaSea));
-                LunaSea newLunaSea = new(values[0], this.logger);
-                notificationManagers.Add(newLunaSea);
-                newLunaSea.SendNotification("Success!", "LunaSea was added to Tranga!");
-                break;
         }
         ExportSettings();
     }
     
     public enum UpdateField { DownloadLocation, Komga, Kavita, Gotify, LunaSea}
+
+    internal class SettingsJsonObject
+    {
+        public TrangaSettings? ts { get; }
+        public CommonObjects? co { get; }
+
+        public SettingsJsonObject(TrangaSettings? ts, CommonObjects? co)
+        {
+            this.ts = ts;
+            this.co = co;
+        }
+    }
 }
\ No newline at end of file
diff --git a/Tranga/TrangaTasks/DownloadChapterTask.cs b/Tranga/TrangaTasks/DownloadChapterTask.cs
index a70e350..8134be6 100644
--- a/Tranga/TrangaTasks/DownloadChapterTask.cs
+++ b/Tranga/TrangaTasks/DownloadChapterTask.cs
@@ -32,10 +32,10 @@ public class DownloadChapterTask : TrangaTask
         HttpStatusCode downloadSuccess = connector.DownloadChapter(this.publication, this.chapter, this, cancellationToken);
         if ((int)downloadSuccess >= 200 && (int)downloadSuccess < 300)
         {
-            foreach(NotificationManager nm in taskManager.settings.notificationManagers)
+            foreach(NotificationManager nm in taskManager.commonObjects.notificationManagers)
                 nm.SendNotification("Chapter downloaded", $"{this.publication.sortName} {this.chapter.chapterNumber} {this.chapter.name}");
 
-            foreach (LibraryManager lm in taskManager.settings.libraryManagers)
+            foreach (LibraryManager lm in taskManager.commonObjects.libraryManagers)
                 lm.UpdateLibrary();
         }
         return downloadSuccess;
diff --git a/Tranga/TrangaTasks/TrangaTask.cs b/Tranga/TrangaTasks/TrangaTask.cs
index b3e4e60..189884c 100644
--- a/Tranga/TrangaTasks/TrangaTask.cs
+++ b/Tranga/TrangaTasks/TrangaTask.cs
@@ -66,7 +66,7 @@ public abstract class TrangaTask
     /// <param name="cancellationToken"></param>
     public void Execute(TaskManager taskManager, CancellationToken? cancellationToken = null)
     {
-        taskManager.settings.logger?.WriteLine(this.GetType().ToString(), $"Executing Task {this}");
+        taskManager.commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Executing Task {this}");
         this.state = ExecutionState.Running;
         this.executionStarted = DateTime.Now;
         this.lastChange = DateTime.Now;
@@ -89,7 +89,7 @@ public abstract class TrangaTask
         if (this is DownloadChapterTask)
             taskManager.DeleteTask(this);
         
-        taskManager.settings.logger?.WriteLine(this.GetType().ToString(), $"Finished Executing Task {this}");
+        taskManager.commonObjects.logger?.WriteLine(this.GetType().ToString(), $"Finished Executing Task {this}");
     }
 
     public void AddChildTask(TrangaTask childTask)