mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Merge pull request #6522 from ferferga/efcore-improvements
This commit is contained in:
commit
c794e48562
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
// Configuration for each entity is in it's own class inside 'ModelConfiguration'.
|
||||||
|
modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDb).Assembly);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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>(
|
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>();
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Jellyfin.Extensions
|
namespace Jellyfin.Extensions
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
using System;
|
namespace Jellyfin.Extensions.Json.Converters
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Jellyfin.Extensions.Json.Converters
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert comma delimited string to array of type.
|
/// Convert comma delimited string to array of type.
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
using System;
|
namespace Jellyfin.Extensions.Json.Converters
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Jellyfin.Extensions.Json.Converters
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert Pipe delimited string to array of type.
|
/// Convert Pipe delimited string to array of type.
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user