Merge pull request #6522 from ferferga/efcore-improvements

pull/6528/head
Claus Vium 3 years ago committed by GitHub
commit c794e48562
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -153,100 +153,10 @@ namespace Jellyfin.Server.Implementations
{
modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc);
base.OnModelCreating(modelBuilder);
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);
}
}
}

@ -1,8 +1,10 @@
using System;
using System.IO;
using System.Linq;
using MediaBrowser.Common.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Implementations
{
@ -13,19 +15,27 @@ namespace Jellyfin.Server.Implementations
{
private readonly IServiceProvider _serviceProvider;
private readonly IApplicationPaths _appPaths;
private readonly ILogger<JellyfinDbProvider> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="JellyfinDbProvider"/> class.
/// </summary>
/// <param name="serviceProvider">The application's service provider.</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;
_appPaths = appPaths;
_logger = logger;
using var jellyfinDb = CreateContext();
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>

@ -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();
}
}
}

@ -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();
}
}
}

@ -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);
}
}
}

@ -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();
}
}
}

@ -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();
}
}
}

@ -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();
}
}
}

@ -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();
}
}
}

@ -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();
}
}
}

@ -78,7 +78,9 @@ namespace Jellyfin.Server
}
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.AddSingleton<IBaseItemManager, BaseItemManager>();

@ -224,7 +224,7 @@ namespace Jellyfin.Server
{
_logger.LogInformation("Running query planner optimizations in the database... This might take a while");
// 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())
{
context.Database.ExecuteSqlRaw("PRAGMA optimize");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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>
/// Convert comma delimited string to array of type.

@ -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>
/// Convert Pipe delimited string to array of type.

@ -1,13 +1,6 @@
using System;
using System.Collections.Generic;
using AutoFixture;
using AutoFixture.AutoMoq;
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;
namespace Jellyfin.Api.Tests.Controllers

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

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

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

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

Loading…
Cancel
Save