Browse Source

Merge pull request #6522 from ferferga/efcore-improvements

Claus Vium 3 years ago
parent
commit
c794e48562
52 changed files with 234 additions and 167 deletions
  1. 0 2
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  2. 0 1
      Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  3. 0 2
      Emby.Server.Implementations/IO/ManagedFileSystem.cs
  4. 0 1
      Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
  5. 0 1
      Jellyfin.Api/Controllers/ApiKeyController.cs
  6. 0 1
      Jellyfin.Api/Controllers/DynamicHlsController.cs
  7. 0 4
      Jellyfin.Api/Controllers/ItemLookupController.cs
  8. 0 1
      Jellyfin.Api/Controllers/LiveTvController.cs
  9. 0 1
      Jellyfin.Api/Controllers/MoviesController.cs
  10. 0 3
      Jellyfin.Api/Controllers/RemoteImageController.cs
  11. 0 1
      Jellyfin.Api/Controllers/SuggestionsController.cs
  12. 0 3
      Jellyfin.Api/Controllers/VideoHlsController.cs
  13. 0 2
      Jellyfin.Api/Controllers/VideosController.cs
  14. 0 2
      Jellyfin.Api/Helpers/AudioHelper.cs
  15. 0 2
      Jellyfin.Api/Helpers/DynamicHlsHelper.cs
  16. 0 1
      Jellyfin.Api/Helpers/HlsHelpers.cs
  17. 0 1
      Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
  18. 0 1
      Jellyfin.Api/Helpers/ProgressiveFileStream.cs
  19. 2 92
      Jellyfin.Server.Implementations/JellyfinDb.cs
  20. 12 2
      Jellyfin.Server.Implementations/JellyfinDbProvider.cs
  21. 20 0
      Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs
  22. 20 0
      Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs
  23. 28 0
      Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs
  24. 20 0
      Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs
  25. 25 0
      Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs
  26. 24 0
      Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs
  27. 21 0
      Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs
  28. 56 0
      Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs
  29. 3 1
      Jellyfin.Server/CoreAppHost.cs
  30. 1 1
      Jellyfin.Server/Program.cs
  31. 0 1
      MediaBrowser.Controller/IServerApplicationHost.cs
  32. 0 1
      MediaBrowser.Controller/Library/NameExtensions.cs
  33. 0 1
      MediaBrowser.Controller/MediaEncoding/JobLogger.cs
  34. 0 1
      MediaBrowser.Controller/Security/IAuthenticationManager.cs
  35. 0 2
      MediaBrowser.Controller/Session/ISessionManager.cs
  36. 0 1
      MediaBrowser.Model/Dlna/DirectPlayProfile.cs
  37. 0 1
      MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
  38. 0 1
      MediaBrowser.Model/Dlna/TranscodingProfile.cs
  39. 0 1
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  40. 0 1
      MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs
  41. 0 1
      MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
  42. 0 1
      MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
  43. 0 1
      MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
  44. 0 1
      RSSDP/SsdpCommunicationsServer.cs
  45. 0 1
      src/Jellyfin.Extensions/DictionaryExtensions.cs
  46. 1 6
      src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs
  47. 1 6
      src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs
  48. 0 7
      tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
  49. 0 1
      tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs
  50. 0 1
      tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
  51. 0 3
      tests/Jellyfin.Server.Tests/ParseNetworkTests.cs
  52. 0 1
      tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs

+ 0 - 2
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -16,7 +16,6 @@ using Emby.Server.Implementations.Playlists;
 using Jellyfin.Data.Enums;
 using Jellyfin.Data.Enums;
 using Jellyfin.Extensions;
 using Jellyfin.Extensions;
 using Jellyfin.Extensions.Json;
 using Jellyfin.Extensions.Json;
-using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
@@ -25,7 +24,6 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Extensions;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;

+ 0 - 1
Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -9,7 +9,6 @@ using System.Net;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Jellyfin.Data.Events;
 using Jellyfin.Networking.Configuration;
 using Jellyfin.Networking.Configuration;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;

+ 0 - 2
Emby.Server.Implementations/IO/ManagedFileSystem.cs

@@ -5,11 +5,9 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
-using System.Runtime.InteropServices;
 using Jellyfin.Extensions;
 using Jellyfin.Extensions;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 
 namespace Emby.Server.Implementations.IO
 namespace Emby.Server.Implementations.IO

+ 0 - 1
Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs

@@ -8,7 +8,6 @@ using System.IO;
 using Emby.Naming.TV;
 using Emby.Naming.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;

+ 0 - 1
Jellyfin.Api/Controllers/ApiKeyController.cs

@@ -1,4 +1,3 @@
-using System;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;

+ 0 - 1
Jellyfin.Api/Controllers/DynamicHlsController.cs

@@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
-using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;

+ 0 - 4
Jellyfin.Api/Controllers/ItemLookupController.cs

@@ -1,13 +1,10 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
-using System.IO;
 using System.Text.Json;
 using System.Text.Json;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Jellyfin.Api.Attributes;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;
-using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
@@ -17,7 +14,6 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Providers;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;

+ 0 - 1
Jellyfin.Api/Controllers/LiveTvController.cs

@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Diagnostics.CodeAnalysis;
 using System.Diagnostics.CodeAnalysis;
-using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Net.Http;
 using System.Net.Http;
 using System.Net.Mime;
 using System.Net.Mime;

+ 0 - 1
Jellyfin.Api/Controllers/MoviesController.cs

@@ -18,7 +18,6 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
 
 
 namespace Jellyfin.Api.Controllers
 namespace Jellyfin.Api.Controllers

+ 0 - 3
Jellyfin.Api/Controllers/RemoteImageController.cs

@@ -4,10 +4,8 @@ using System.ComponentModel.DataAnnotations;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Net.Http;
 using System.Net.Http;
-using System.Net.Mime;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Jellyfin.Api.Attributes;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
@@ -16,7 +14,6 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Providers;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;

+ 0 - 1
Jellyfin.Api/Controllers/SuggestionsController.cs

@@ -1,6 +1,5 @@
 using System;
 using System;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
-using System.Linq;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Extensions;
 using Jellyfin.Api.Extensions;
 using Jellyfin.Api.ModelBinders;
 using Jellyfin.Api.ModelBinders;

+ 0 - 3
Jellyfin.Api/Controllers/VideoHlsController.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
-using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Attributes;
 using Jellyfin.Api.Attributes;
@@ -20,12 +19,10 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 
 namespace Jellyfin.Api.Controllers
 namespace Jellyfin.Api.Controllers

+ 0 - 2
Jellyfin.Api/Controllers/VideosController.cs

@@ -25,14 +25,12 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
 
 
 namespace Jellyfin.Api.Controllers
 namespace Jellyfin.Api.Controllers
 {
 {

+ 0 - 2
Jellyfin.Api/Helpers/AudioHelper.cs

@@ -11,12 +11,10 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
 
 
 namespace Jellyfin.Api.Helpers
 namespace Jellyfin.Api.Helpers
 {
 {

+ 0 - 2
Jellyfin.Api/Helpers/DynamicHlsHelper.cs

@@ -18,11 +18,9 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using Microsoft.Net.Http.Headers;
 using Microsoft.Net.Http.Headers;
 
 

+ 0 - 1
Jellyfin.Api/Helpers/HlsHelpers.cs

@@ -1,7 +1,6 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
-using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Models.StreamingDtos;
 using Jellyfin.Api.Models.StreamingDtos;

+ 0 - 1
Jellyfin.Api/Helpers/ProgressiveFileCopier.cs

@@ -1,7 +1,6 @@
 using System;
 using System;
 using System.Buffers;
 using System.Buffers;
 using System.IO;
 using System.IO;
-using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Models.PlaybackDtos;
 using Jellyfin.Api.Models.PlaybackDtos;

+ 0 - 1
Jellyfin.Api/Helpers/ProgressiveFileStream.cs

@@ -1,7 +1,6 @@
 using System;
 using System;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.IO;
 using System.IO;
-using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Models.PlaybackDtos;
 using Jellyfin.Api.Models.PlaybackDtos;

+ 2 - 92
Jellyfin.Server.Implementations/JellyfinDb.cs

@@ -153,100 +153,10 @@ namespace Jellyfin.Server.Implementations
         {
         {
             modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
             modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
             base.OnModelCreating(modelBuilder);
             base.OnModelCreating(modelBuilder);
-
             modelBuilder.HasDefaultSchema("jellyfin");
             modelBuilder.HasDefaultSchema("jellyfin");
 
 
-            // Collations
-
-            modelBuilder.Entity<User>()
-                .Property(user => user.Username)
-                .UseCollation("NOCASE");
-
-            // Delete behavior
-
-            modelBuilder.Entity<User>()
-                .HasOne(u => u.ProfileImage)
-                .WithOne()
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<User>()
-                .HasMany(u => u.Permissions)
-                .WithOne()
-                .HasForeignKey(p => p.UserId)
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<User>()
-                .HasMany(u => u.Preferences)
-                .WithOne()
-                .HasForeignKey(p => p.UserId)
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<User>()
-                .HasMany(u => u.AccessSchedules)
-                .WithOne()
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<User>()
-                .HasMany(u => u.DisplayPreferences)
-                .WithOne()
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<User>()
-                .HasMany(u => u.ItemDisplayPreferences)
-                .WithOne()
-                .OnDelete(DeleteBehavior.Cascade);
-
-            modelBuilder.Entity<DisplayPreferences>()
-                .HasMany(d => d.HomeSections)
-                .WithOne()
-                .OnDelete(DeleteBehavior.Cascade);
-
-            // Indexes
-
-            modelBuilder.Entity<ApiKey>()
-                .HasIndex(entity => entity.AccessToken)
-                .IsUnique();
-
-            modelBuilder.Entity<User>()
-                .HasIndex(entity => entity.Username)
-                .IsUnique();
-
-            modelBuilder.Entity<Device>()
-                .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity });
-
-            modelBuilder.Entity<Device>()
-                .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity });
-
-            modelBuilder.Entity<Device>()
-                .HasIndex(entity => new { entity.UserId, entity.DeviceId });
-
-            modelBuilder.Entity<Device>()
-                .HasIndex(entity => entity.DeviceId);
-
-            modelBuilder.Entity<DeviceOptions>()
-                .HasIndex(entity => entity.DeviceId)
-                .IsUnique();
-
-            modelBuilder.Entity<DisplayPreferences>()
-                .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
-                .IsUnique();
-
-            modelBuilder.Entity<CustomItemDisplayPreferences>()
-                .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
-                .IsUnique();
-
-            // Used to get a user's permissions or a specific permission for a user.
-            // Also prevents multiple values being created for a user.
-            // Filtered over non-null user ids for when other entities (groups, API keys) get permissions
-            modelBuilder.Entity<Permission>()
-                .HasIndex(p => new { p.UserId, p.Kind })
-                .HasFilter("[UserId] IS NOT NULL")
-                .IsUnique();
-
-            modelBuilder.Entity<Preference>()
-                .HasIndex(p => new { p.UserId, p.Kind })
-                .HasFilter("[UserId] IS NOT NULL")
-                .IsUnique();
+            // Configuration for each entity is in it's own class inside 'ModelConfiguration'.
+            modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDb).Assembly);
         }
         }
     }
     }
 }
 }

+ 12 - 2
Jellyfin.Server.Implementations/JellyfinDbProvider.cs

@@ -1,8 +1,10 @@
 using System;
 using System;
 using System.IO;
 using System.IO;
+using System.Linq;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
 
 
 namespace Jellyfin.Server.Implementations
 namespace Jellyfin.Server.Implementations
 {
 {
@@ -13,19 +15,27 @@ namespace Jellyfin.Server.Implementations
     {
     {
         private readonly IServiceProvider _serviceProvider;
         private readonly IServiceProvider _serviceProvider;
         private readonly IApplicationPaths _appPaths;
         private readonly IApplicationPaths _appPaths;
+        private readonly ILogger<JellyfinDbProvider> _logger;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="JellyfinDbProvider"/> class.
         /// Initializes a new instance of the <see cref="JellyfinDbProvider"/> class.
         /// </summary>
         /// </summary>
         /// <param name="serviceProvider">The application's service provider.</param>
         /// <param name="serviceProvider">The application's service provider.</param>
         /// <param name="appPaths">The application paths.</param>
         /// <param name="appPaths">The application paths.</param>
-        public JellyfinDbProvider(IServiceProvider serviceProvider, IApplicationPaths appPaths)
+        /// <param name="logger">The logger.</param>
+        public JellyfinDbProvider(IServiceProvider serviceProvider, IApplicationPaths appPaths, ILogger<JellyfinDbProvider> logger)
         {
         {
             _serviceProvider = serviceProvider;
             _serviceProvider = serviceProvider;
             _appPaths = appPaths;
             _appPaths = appPaths;
+            _logger = logger;
 
 
             using var jellyfinDb = CreateContext();
             using var jellyfinDb = CreateContext();
-            jellyfinDb.Database.Migrate();
+            if (jellyfinDb.Database.GetPendingMigrations().Any())
+            {
+                _logger.LogInformation("There are pending EFCore migrations in the database. Applying... (This may take a while, do not stop Jellyfin)");
+                jellyfinDb.Database.Migrate();
+                _logger.LogInformation("EFCore migrations applied successfully");
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 20 - 0
Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs

@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the ApiKey entity.
+    /// </summary>
+    public class ApiKeyConfiguration : IEntityTypeConfiguration<ApiKey>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<ApiKey> builder)
+        {
+            builder
+                .HasIndex(entity => entity.AccessToken)
+                .IsUnique();
+        }
+    }
+}

+ 20 - 0
Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs

@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the CustomItemDisplayPreferences entity.
+    /// </summary>
+    public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration<CustomItemDisplayPreferences>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<CustomItemDisplayPreferences> builder)
+        {
+            builder
+                .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
+                .IsUnique();
+        }
+    }
+}

+ 28 - 0
Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs

@@ -0,0 +1,28 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the Device entity.
+    /// </summary>
+    public class DeviceConfiguration : IEntityTypeConfiguration<Device>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<Device> builder)
+        {
+            builder
+                .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity });
+
+            builder
+                .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity });
+
+            builder
+                .HasIndex(entity => new { entity.UserId, entity.DeviceId });
+
+            builder
+                .HasIndex(entity => entity.DeviceId);
+        }
+    }
+}

+ 20 - 0
Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs

@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the DeviceOptions entity.
+    /// </summary>
+    public class DeviceOptionsConfiguration : IEntityTypeConfiguration<DeviceOptions>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<DeviceOptions> builder)
+        {
+            builder
+                .HasIndex(entity => entity.DeviceId)
+                .IsUnique();
+        }
+    }
+}

+ 25 - 0
Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs

@@ -0,0 +1,25 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the DisplayPreferencesConfiguration entity.
+    /// </summary>
+    public class DisplayPreferencesConfiguration : IEntityTypeConfiguration<DisplayPreferences>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<DisplayPreferences> builder)
+        {
+            builder
+                .HasMany(d => d.HomeSections)
+                .WithOne()
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
+                .IsUnique();
+        }
+    }
+}

+ 24 - 0
Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs

@@ -0,0 +1,24 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the Permission entity.
+    /// </summary>
+    public class PermissionConfiguration : IEntityTypeConfiguration<Permission>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<Permission> builder)
+        {
+            // Used to get a user's permissions or a specific permission for a user.
+            // Also prevents multiple values being created for a user.
+            // Filtered over non-null user ids for when other entities (groups, API keys) get permissions
+            builder
+                .HasIndex(p => new { p.UserId, p.Kind })
+                .HasFilter("[UserId] IS NOT NULL")
+                .IsUnique();
+        }
+    }
+}

+ 21 - 0
Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs

@@ -0,0 +1,21 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the Permission entity.
+    /// </summary>
+    public class PreferenceConfiguration : IEntityTypeConfiguration<Preference>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<Preference> builder)
+        {
+            builder
+                .HasIndex(p => new { p.UserId, p.Kind })
+                .HasFilter("[UserId] IS NOT NULL")
+                .IsUnique();
+        }
+    }
+}

+ 56 - 0
Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs

@@ -0,0 +1,56 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+    /// <summary>
+    /// FluentAPI configuration for the User entity.
+    /// </summary>
+    public class UserConfiguration : IEntityTypeConfiguration<User>
+    {
+        /// <inheritdoc/>
+        public void Configure(EntityTypeBuilder<User> builder)
+        {
+            builder
+                .Property(user => user.Username)
+                .UseCollation("NOCASE");
+
+            builder
+                .HasOne(u => u.ProfileImage)
+                .WithOne()
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasMany(u => u.Permissions)
+                .WithOne()
+                .HasForeignKey(p => p.UserId)
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasMany(u => u.Preferences)
+                .WithOne()
+                .HasForeignKey(p => p.UserId)
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasMany(u => u.AccessSchedules)
+                .WithOne()
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasMany(u => u.DisplayPreferences)
+                .WithOne()
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasMany(u => u.ItemDisplayPreferences)
+                .WithOne()
+                .OnDelete(DeleteBehavior.Cascade);
+
+            builder
+                .HasIndex(entity => entity.Username)
+                .IsUnique();
+        }
+    }
+}

+ 3 - 1
Jellyfin.Server/CoreAppHost.cs

@@ -78,7 +78,9 @@ namespace Jellyfin.Server
             }
             }
 
 
             ServiceCollection.AddDbContextPool<JellyfinDb>(
             ServiceCollection.AddDbContextPool<JellyfinDb>(
-                 options => options.UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"));
+                 options => options
+                    .UseLoggerFactory(LoggerFactory)
+                    .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"));
 
 
             ServiceCollection.AddEventServices();
             ServiceCollection.AddEventServices();
             ServiceCollection.AddSingleton<IBaseItemManager, BaseItemManager>();
             ServiceCollection.AddSingleton<IBaseItemManager, BaseItemManager>();

+ 1 - 1
Jellyfin.Server/Program.cs

@@ -224,7 +224,7 @@ namespace Jellyfin.Server
             {
             {
                 _logger.LogInformation("Running query planner optimizations in the database... This might take a while");
                 _logger.LogInformation("Running query planner optimizations in the database... This might take a while");
                 // Run before disposing the application
                 // Run before disposing the application
-                using var context = new JellyfinDbProvider(appHost.ServiceProvider, appPaths).CreateContext();
+                using var context = appHost.Resolve<JellyfinDbProvider>().CreateContext();
                 if (context.Database.IsSqlite())
                 if (context.Database.IsSqlite())
                 {
                 {
                     context.Database.ExecuteSqlRaw("PRAGMA optimize");
                     context.Database.ExecuteSqlRaw("PRAGMA optimize");

+ 0 - 1
MediaBrowser.Controller/IServerApplicationHost.cs

@@ -2,7 +2,6 @@
 
 
 #pragma warning disable CS1591
 #pragma warning disable CS1591
 
 
-using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Net;
 using System.Net;
 using MediaBrowser.Common;
 using MediaBrowser.Common;

+ 0 - 1
MediaBrowser.Controller/Library/NameExtensions.cs

@@ -4,7 +4,6 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using Diacritics.Extensions;
 using Diacritics.Extensions;
-using MediaBrowser.Controller.Extensions;
 
 
 namespace MediaBrowser.Controller.Library
 namespace MediaBrowser.Controller.Library
 {
 {

+ 0 - 1
MediaBrowser.Controller/MediaEncoding/JobLogger.cs

@@ -6,7 +6,6 @@ using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
-using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 
 

+ 0 - 1
MediaBrowser.Controller/Security/IAuthenticationManager.cs

@@ -1,6 +1,5 @@
 #nullable enable
 #nullable enable
 
 
-using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 

+ 0 - 2
MediaBrowser.Controller/Session/ISessionManager.cs

@@ -10,8 +10,6 @@ using Jellyfin.Data.Entities.Security;
 using Jellyfin.Data.Events;
 using Jellyfin.Data.Events;
 using MediaBrowser.Controller.Authentication;
 using MediaBrowser.Controller.Authentication;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Model.Devices;
 using MediaBrowser.Model.Session;
 using MediaBrowser.Model.Session;
 using MediaBrowser.Model.SyncPlay;
 using MediaBrowser.Model.SyncPlay;
 
 

+ 0 - 1
MediaBrowser.Model/Dlna/DirectPlayProfile.cs

@@ -1,6 +1,5 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
 
 
-using System.ComponentModel.DataAnnotations;
 using System.Xml.Serialization;
 using System.Xml.Serialization;
 
 
 namespace MediaBrowser.Model.Dlna
 namespace MediaBrowser.Model.Dlna

+ 0 - 1
MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs

@@ -4,7 +4,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
-using System.Linq;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 
 
 namespace MediaBrowser.Model.Dlna
 namespace MediaBrowser.Model.Dlna

+ 0 - 1
MediaBrowser.Model/Dlna/TranscodingProfile.cs

@@ -1,7 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
 
 
 using System.ComponentModel;
 using System.ComponentModel;
-using System.ComponentModel.DataAnnotations;
 using System.Xml.Serialization;
 using System.Xml.Serialization;
 
 
 namespace MediaBrowser.Model.Dlna
 namespace MediaBrowser.Model.Dlna

+ 0 - 1
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -2,7 +2,6 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;

+ 0 - 1
MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs

@@ -2,7 +2,6 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;

+ 0 - 1
MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs

@@ -2,7 +2,6 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.IO;
 using System.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;

+ 0 - 1
MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs

@@ -12,7 +12,6 @@ using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Xml;
 using System.Xml;
-using MediaBrowser.Common;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;

+ 0 - 1
MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs

@@ -1,7 +1,6 @@
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
-using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Xml;
 using System.Xml;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;

+ 0 - 1
RSSDP/SsdpCommunicationsServer.cs

@@ -1,6 +1,5 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
 using System.Net.Http;
 using System.Net.Http;

+ 0 - 1
src/Jellyfin.Extensions/DictionaryExtensions.cs

@@ -1,4 +1,3 @@
-using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace Jellyfin.Extensions
 namespace Jellyfin.Extensions

+ 1 - 6
src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs

@@ -1,9 +1,4 @@
-using System;
-using System.ComponentModel;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace Jellyfin.Extensions.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
 {
 {
     /// <summary>
     /// <summary>
     /// Convert comma delimited string to array of type.
     /// Convert comma delimited string to array of type.

+ 1 - 6
src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs

@@ -1,9 +1,4 @@
-using System;
-using System.ComponentModel;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace Jellyfin.Extensions.Json.Converters
+namespace Jellyfin.Extensions.Json.Converters
 {
 {
     /// <summary>
     /// <summary>
     /// Convert Pipe delimited string to array of type.
     /// Convert Pipe delimited string to array of type.

+ 0 - 7
tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs

@@ -1,13 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using AutoFixture;
-using AutoFixture.AutoMoq;
 using Jellyfin.Api.Controllers;
 using Jellyfin.Api.Controllers;
-using Jellyfin.Api.Helpers;
-using Jellyfin.Api.Models.StreamingDtos;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using Moq;
 using Xunit;
 using Xunit;
 
 
 namespace Jellyfin.Api.Tests.Controllers
 namespace Jellyfin.Api.Tests.Controllers

+ 0 - 1
tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs

@@ -1,4 +1,3 @@
-using System.Globalization;
 using System.Text.Json;
 using System.Text.Json;
 using FsCheck;
 using FsCheck;
 using FsCheck.Xunit;
 using FsCheck.Xunit;

+ 0 - 1
tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs

@@ -4,7 +4,6 @@ using System.IO;
 using System.Text.Json;
 using System.Text.Json;
 using Jellyfin.Extensions.Json;
 using Jellyfin.Extensions.Json;
 using MediaBrowser.MediaEncoding.Probing;
 using MediaBrowser.MediaEncoding.Probing;
-using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
 using Microsoft.Extensions.Logging.Abstractions;
 using Microsoft.Extensions.Logging.Abstractions;

+ 0 - 3
tests/Jellyfin.Server.Tests/ParseNetworkTests.cs

@@ -1,9 +1,6 @@
 using System;
 using System;
-using System.Collections.Generic;
-using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
-using System.Text;
 using Jellyfin.Networking.Configuration;
 using Jellyfin.Networking.Configuration;
 using Jellyfin.Networking.Manager;
 using Jellyfin.Networking.Manager;
 using Jellyfin.Server.Extensions;
 using Jellyfin.Server.Extensions;

+ 0 - 1
tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs

@@ -11,7 +11,6 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.System;
 using MediaBrowser.Providers.Plugins.Tmdb.Movies;
 using MediaBrowser.Providers.Plugins.Tmdb.Movies;
 using MediaBrowser.XbmcMetadata.Parsers;
 using MediaBrowser.XbmcMetadata.Parsers;
 using Microsoft.Extensions.Logging.Abstractions;
 using Microsoft.Extensions.Logging.Abstractions;