aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs288
-rw-r--r--Emby.Server.Implementations/Activity/ActivityManager.cs70
-rw-r--r--Emby.Server.Implementations/Activity/ActivityRepository.cs308
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs14
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj5
-rw-r--r--Jellyfin.Data/DbContexts/Jellyfin.cs1140
-rw-r--r--Jellyfin.Data/Entities/ActivityLog.cs153
-rw-r--r--Jellyfin.Data/ISavingChanges.cs9
-rw-r--r--Jellyfin.Data/Jellyfin.Data.csproj24
-rw-r--r--Jellyfin.Server.Implementations/Activity/ActivityManager.cs103
-rw-r--r--Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj34
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDb.cs119
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDbProvider.cs33
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.Designer.cs1513
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.cs1294
-rw-r--r--Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs20
-rw-r--r--Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs1511
-rw-r--r--Jellyfin.Server/Jellyfin.Server.csproj7
-rw-r--r--Jellyfin.Server/Migrations/MigrationRunner.cs3
-rw-r--r--Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs109
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs11
-rw-r--r--MediaBrowser.Api/System/ActivityLogService.cs2
-rw-r--r--MediaBrowser.Model/Activity/ActivityLogEntry.cs1
-rw-r--r--MediaBrowser.Model/Activity/IActivityManager.cs15
-rw-r--r--MediaBrowser.Model/Activity/IActivityRepository.cs14
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj3
-rw-r--r--MediaBrowser.sln46
27 files changed, 5147 insertions, 1702 deletions
diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
index 4685a03ac..54894fd65 100644
--- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
+++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
@@ -4,11 +4,11 @@ using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
@@ -104,47 +104,53 @@ namespace Emby.Server.Implementations.Activity
return Task.CompletedTask;
}
- private void OnCameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
+ private async void OnCameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("CameraImageUploadedFrom"),
e.Argument.Device.Name),
- Type = NotificationType.CameraImageUploaded.ToString()
- });
+ NotificationType.CameraImageUploaded.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnUserLockedOut(object sender, GenericEventArgs<User> e)
+ private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserLockedOutWithName"),
e.Argument.Name),
- Type = NotificationType.UserLockedOut.ToString(),
- UserId = e.Argument.Id
- });
+ NotificationType.UserLockedOut.ToString(),
+ e.Argument.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
+ private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
e.Provider,
- Notifications.NotificationEntryPoint.GetItemName(e.Item)),
- Type = "SubtitleDownloadFailure",
+ Emby.Notifications.NotificationEntryPoint.GetItemName(e.Item)),
+ "SubtitleDownloadFailure",
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture),
ShortOverview = e.Exception.Message
- });
+ }).ConfigureAwait(false);
}
- private void OnPlaybackStopped(object sender, PlaybackStopEventArgs e)
+ private async void OnPlaybackStopped(object sender, PlaybackStopEventArgs e)
{
var item = e.MediaInfo;
@@ -167,20 +173,21 @@ namespace Emby.Server.Implementations.Activity
var user = e.Users[0];
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"),
user.Name,
GetItemName(item),
e.DeviceName),
- Type = GetPlaybackStoppedNotificationType(item.MediaType),
- UserId = user.Id
- });
+ GetPlaybackStoppedNotificationType(item.MediaType),
+ user.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnPlaybackStart(object sender, PlaybackProgressEventArgs e)
+ private async void OnPlaybackStart(object sender, PlaybackProgressEventArgs e)
{
var item = e.MediaInfo;
@@ -203,17 +210,18 @@ namespace Emby.Server.Implementations.Activity
var user = e.Users.First();
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserStartedPlayingItemWithValues"),
user.Name,
GetItemName(item),
e.DeviceName),
- Type = GetPlaybackNotificationType(item.MediaType),
- UserId = user.Id
- });
+ GetPlaybackNotificationType(item.MediaType),
+ user.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
private static string GetItemName(BaseItemDto item)
@@ -263,7 +271,7 @@ namespace Emby.Server.Implementations.Activity
return null;
}
- private void OnSessionEnded(object sender, SessionEventArgs e)
+ private async void OnSessionEnded(object sender, SessionEventArgs e)
{
var session = e.SessionInfo;
@@ -272,110 +280,120 @@ namespace Emby.Server.Implementations.Activity
return;
}
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserOfflineFromDevice"),
session.UserName,
session.DeviceName),
- Type = "SessionEnded",
+ "SessionEnded",
+ session.UserId,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("LabelIpAddressValue"),
session.RemoteEndPoint),
- UserId = session.UserId
- });
+ }).ConfigureAwait(false);
}
- private void OnAuthenticationSucceeded(object sender, GenericEventArgs<AuthenticationResult> e)
+ private async void OnAuthenticationSucceeded(object sender, GenericEventArgs<AuthenticationResult> e)
{
var user = e.Argument.User;
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("AuthenticationSucceededWithUserName"),
user.Name),
- Type = "AuthenticationSucceeded",
+ "AuthenticationSucceeded",
+ user.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("LabelIpAddressValue"),
e.Argument.SessionInfo.RemoteEndPoint),
- UserId = user.Id
- });
+ }).ConfigureAwait(false);
}
- private void OnAuthenticationFailed(object sender, GenericEventArgs<AuthenticationRequest> e)
+ private async void OnAuthenticationFailed(object sender, GenericEventArgs<AuthenticationRequest> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("FailedLoginAttemptWithUserName"),
e.Argument.Username),
- Type = "AuthenticationFailed",
+ "AuthenticationFailed",
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Error)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("LabelIpAddressValue"),
e.Argument.RemoteEndPoint),
- Severity = LogLevel.Error
- });
+ }).ConfigureAwait(false);
}
- private void OnUserPolicyUpdated(object sender, GenericEventArgs<User> e)
+ private async void OnUserPolicyUpdated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserPolicyUpdatedWithName"),
e.Argument.Name),
- Type = "UserPolicyUpdated",
- UserId = e.Argument.Id
- });
+ "UserPolicyUpdated",
+ e.Argument.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnUserDeleted(object sender, GenericEventArgs<User> e)
+ private async void OnUserDeleted(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserDeletedWithName"),
e.Argument.Name),
- Type = "UserDeleted"
- });
+ "UserDeleted",
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnUserPasswordChanged(object sender, GenericEventArgs<User> e)
+ private async void OnUserPasswordChanged(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserPasswordChangedWithName"),
e.Argument.Name),
- Type = "UserPasswordChanged",
- UserId = e.Argument.Id
- });
+ "UserPasswordChanged",
+ e.Argument.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace)).ConfigureAwait(false);
}
- private void OnUserCreated(object sender, GenericEventArgs<User> e)
+ private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserCreatedWithName"),
e.Argument.Name),
- Type = "UserCreated",
- UserId = e.Argument.Id
- });
+ "UserCreated",
+ e.Argument.Id,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnSessionStarted(object sender, SessionEventArgs e)
+ private async void OnSessionStarted(object sender, SessionEventArgs e)
{
var session = e.SessionInfo;
@@ -384,87 +402,100 @@ namespace Emby.Server.Implementations.Activity
return;
}
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserOnlineFromDevice"),
session.UserName,
session.DeviceName),
- Type = "SessionStarted",
+ "SessionStarted",
+ session.UserId,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("LabelIpAddressValue"),
- session.RemoteEndPoint),
- UserId = session.UserId
- });
+ session.RemoteEndPoint)
+ }).ConfigureAwait(false);
}
- private void OnPluginUpdated(object sender, GenericEventArgs<(IPlugin, VersionInfo)> e)
+ private async void OnPluginUpdated(object sender, GenericEventArgs<(IPlugin, VersionInfo)> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("PluginUpdatedWithName"),
e.Argument.Item1.Name),
- Type = NotificationType.PluginUpdateInstalled.ToString(),
+ NotificationType.PluginUpdateInstalled.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("VersionNumber"),
e.Argument.Item2.version),
Overview = e.Argument.Item2.changelog
- });
+ }).ConfigureAwait(false);
}
- private void OnPluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
+ private async void OnPluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("PluginUninstalledWithName"),
e.Argument.Name),
- Type = NotificationType.PluginUninstalled.ToString()
- });
+ NotificationType.PluginUninstalled.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace))
+ .ConfigureAwait(false);
}
- private void OnPluginInstalled(object sender, GenericEventArgs<VersionInfo> e)
+ private async void OnPluginInstalled(object sender, GenericEventArgs<VersionInfo> e)
{
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("PluginInstalledWithName"),
e.Argument.name),
- Type = NotificationType.PluginInstalled.ToString(),
+ NotificationType.PluginInstalled.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("VersionNumber"),
e.Argument.version)
- });
+ }).ConfigureAwait(false);
}
- private void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e)
+ private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e)
{
var installationInfo = e.InstallationInfo;
- CreateLogEntry(new ActivityLogEntry
- {
- Name = string.Format(
+ await CreateLogEntry(new ActivityLog(
+ string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("NameInstallFailed"),
installationInfo.Name),
- Type = NotificationType.InstallationFailed.ToString(),
+ NotificationType.InstallationFailed.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Trace)
+ {
ShortOverview = string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("VersionNumber"),
installationInfo.Version),
Overview = e.Exception.Message
- });
+ }).ConfigureAwait(false);
}
- private void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
+ private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
{
var result = e.Result;
var task = e.Task;
@@ -495,22 +526,21 @@ namespace Emby.Server.Implementations.Activity
vals.Add(e.Result.LongErrorMessage);
}
- CreateLogEntry(new ActivityLogEntry
+ await CreateLogEntry(new ActivityLog(
+ string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
+ NotificationType.TaskFailed.ToString(),
+ Guid.Empty,
+ DateTime.UtcNow,
+ LogLevel.Error)
{
- Name = string.Format(
- CultureInfo.InvariantCulture,
- _localization.GetLocalizedString("ScheduledTaskFailedWithName"),
- task.Name),
- Type = NotificationType.TaskFailed.ToString(),
Overview = string.Join(Environment.NewLine, vals),
- ShortOverview = runningTime,
- Severity = LogLevel.Error
- });
+ ShortOverview = runningTime
+ }).ConfigureAwait(false);
}
}
- private void CreateLogEntry(ActivityLogEntry entry)
- => _activityManager.Create(entry);
+ private async Task CreateLogEntry(ActivityLog entry)
+ => await _activityManager.CreateAsync(entry).ConfigureAwait(false);
/// <inheritdoc />
public void Dispose()
@@ -558,7 +588,7 @@ namespace Emby.Server.Implementations.Activity
{
int years = days / DaysInYear;
values.Add(CreateValueString(years, "year"));
- days %= DaysInYear;
+ days = days % DaysInYear;
}
// Number of months
@@ -566,7 +596,7 @@ namespace Emby.Server.Implementations.Activity
{
int months = days / DaysInMonth;
values.Add(CreateValueString(months, "month"));
- days %= DaysInMonth;
+ days = days % DaysInMonth;
}
// Number of days
diff --git a/Emby.Server.Implementations/Activity/ActivityManager.cs b/Emby.Server.Implementations/Activity/ActivityManager.cs
deleted file mode 100644
index 81bebae3d..000000000
--- a/Emby.Server.Implementations/Activity/ActivityManager.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Activity;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Querying;
-
-namespace Emby.Server.Implementations.Activity
-{
- /// <summary>
- /// The activity log manager.
- /// </summary>
- public class ActivityManager : IActivityManager
- {
- private readonly IActivityRepository _repo;
- private readonly IUserManager _userManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ActivityManager"/> class.
- /// </summary>
- /// <param name="repo">The activity repository.</param>
- /// <param name="userManager">The user manager.</param>
- public ActivityManager(IActivityRepository repo, IUserManager userManager)
- {
- _repo = repo;
- _userManager = userManager;
- }
-
- /// <inheritdoc />
- public event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
-
- public void Create(ActivityLogEntry entry)
- {
- entry.Date = DateTime.UtcNow;
-
- _repo.Create(entry);
-
- EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(entry));
- }
-
- /// <inheritdoc />
- public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit)
- {
- var result = _repo.GetActivityLogEntries(minDate, hasUserId, startIndex, limit);
-
- foreach (var item in result.Items)
- {
- if (item.UserId == Guid.Empty)
- {
- continue;
- }
-
- var user = _userManager.GetUserById(item.UserId);
-
- if (user != null)
- {
- var dto = _userManager.GetUserDto(user);
- item.UserPrimaryImageTag = dto.PrimaryImageTag;
- }
- }
-
- return result;
- }
-
- /// <inheritdoc />
- public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit)
- {
- return GetActivityLogEntries(minDate, null, startIndex, limit);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
deleted file mode 100644
index 22796ba3f..000000000
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using Emby.Server.Implementations.Data;
-using MediaBrowser.Controller;
-using MediaBrowser.Model.Activity;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Querying;
-using Microsoft.Extensions.Logging;
-using SQLitePCL.pretty;
-
-namespace Emby.Server.Implementations.Activity
-{
- /// <summary>
- /// The activity log repository.
- /// </summary>
- public class ActivityRepository : BaseSqliteRepository, IActivityRepository
- {
- private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLog";
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ActivityRepository"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="appPaths">The server application paths.</param>
- /// <param name="fileSystem">The filesystem.</param>
- public ActivityRepository(ILogger<ActivityRepository> logger, IServerApplicationPaths appPaths, IFileSystem fileSystem)
- : base(logger)
- {
- DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db");
- _fileSystem = fileSystem;
- }
-
- /// <summary>
- /// Initializes the <see cref="ActivityRepository"/>.
- /// </summary>
- public void Initialize()
- {
- try
- {
- InitializeInternal();
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error loading database file. Will reset and retry.");
-
- _fileSystem.DeleteFile(DbFilePath);
-
- InitializeInternal();
- }
- }
-
- private void InitializeInternal()
- {
- using var connection = GetConnection();
- connection.RunQueries(new[]
- {
- "create table if not exists ActivityLog (Id INTEGER PRIMARY KEY, Name TEXT NOT NULL, Overview TEXT, ShortOverview TEXT, Type TEXT NOT NULL, ItemId TEXT, UserId TEXT, DateCreated DATETIME NOT NULL, LogSeverity TEXT NOT NULL)",
- "drop index if exists idx_ActivityLogEntries"
- });
-
- TryMigrate(connection);
- }
-
- private void TryMigrate(ManagedConnection connection)
- {
- try
- {
- if (TableExists(connection, "ActivityLogEntries"))
- {
- connection.RunQueries(new[]
- {
- "INSERT INTO ActivityLog (Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) SELECT Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity FROM ActivityLogEntries",
- "drop table if exists ActivityLogEntries"
- });
- }
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error migrating activity log database");
- }
- }
-
- /// <inheritdoc />
- public void Create(ActivityLogEntry entry)
- {
- if (entry == null)
- {
- throw new ArgumentNullException(nameof(entry));
- }
-
- using var connection = GetConnection();
- connection.RunInTransaction(db =>
- {
- using var statement = db.PrepareStatement("insert into ActivityLog (Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)");
- statement.TryBind("@Name", entry.Name);
-
- statement.TryBind("@Overview", entry.Overview);
- statement.TryBind("@ShortOverview", entry.ShortOverview);
- statement.TryBind("@Type", entry.Type);
- statement.TryBind("@ItemId", entry.ItemId);
-
- if (entry.UserId.Equals(Guid.Empty))
- {
- statement.TryBindNull("@UserId");
- }
- else
- {
- statement.TryBind("@UserId", entry.UserId.ToString("N", CultureInfo.InvariantCulture));
- }
-
- statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
- statement.TryBind("@LogSeverity", entry.Severity.ToString());
-
- statement.MoveNext();
- }, TransactionMode);
- }
-
- /// <summary>
- /// Adds the provided <see cref="ActivityLogEntry"/> to this repository.
- /// </summary>
- /// <param name="entry">The activity log entry.</param>
- /// <exception cref="ArgumentNullException">If entry is null.</exception>
- public void Update(ActivityLogEntry entry)
- {
- if (entry == null)
- {
- throw new ArgumentNullException(nameof(entry));
- }
-
- using var connection = GetConnection();
- connection.RunInTransaction(db =>
- {
- using var statement = db.PrepareStatement("Update ActivityLog set Name=@Name,Overview=@Overview,ShortOverview=@ShortOverview,Type=@Type,ItemId=@ItemId,UserId=@UserId,DateCreated=@DateCreated,LogSeverity=@LogSeverity where Id=@Id");
- statement.TryBind("@Id", entry.Id);
-
- statement.TryBind("@Name", entry.Name);
- statement.TryBind("@Overview", entry.Overview);
- statement.TryBind("@ShortOverview", entry.ShortOverview);
- statement.TryBind("@Type", entry.Type);
- statement.TryBind("@ItemId", entry.ItemId);
-
- if (entry.UserId.Equals(Guid.Empty))
- {
- statement.TryBindNull("@UserId");
- }
- else
- {
- statement.TryBind("@UserId", entry.UserId.ToString("N", CultureInfo.InvariantCulture));
- }
-
- statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
- statement.TryBind("@LogSeverity", entry.Severity.ToString());
-
- statement.MoveNext();
- }, TransactionMode);
- }
-
- /// <inheritdoc />
- public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit)
- {
- var commandText = BaseActivitySelectText;
- var whereClauses = new List<string>();
-
- if (minDate.HasValue)
- {
- whereClauses.Add("DateCreated>=@DateCreated");
- }
-
- if (hasUserId.HasValue)
- {
- whereClauses.Add(hasUserId.Value ? "UserId not null" : "UserId is null");
- }
-
- var whereTextWithoutPaging = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
-
- if (startIndex.HasValue && startIndex.Value > 0)
- {
- var pagingWhereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
-
- whereClauses.Add(
- string.Format(
- CultureInfo.InvariantCulture,
- "Id NOT IN (SELECT Id FROM ActivityLog {0} ORDER BY DateCreated DESC LIMIT {1})",
- pagingWhereText,
- startIndex.Value));
- }
-
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses.ToArray());
-
- commandText += whereText;
-
- commandText += " ORDER BY DateCreated DESC";
-
- if (limit.HasValue)
- {
- commandText += " LIMIT " + limit.Value.ToString(CultureInfo.InvariantCulture);
- }
-
- var statementTexts = new[]
- {
- commandText,
- "select count (Id) from ActivityLog" + whereTextWithoutPaging
- };
-
- var list = new List<ActivityLogEntry>();
- var result = new QueryResult<ActivityLogEntry>();
-
- using var connection = GetConnection(true);
- connection.RunInTransaction(
- db =>
- {
- var statements = PrepareAll(db, statementTexts).ToList();
-
- using (var statement = statements[0])
- {
- if (minDate.HasValue)
- {
- statement.TryBind("@DateCreated", minDate.Value.ToDateTimeParamValue());
- }
-
- list.AddRange(statement.ExecuteQuery().Select(GetEntry));
- }
-
- using (var statement = statements[1])
- {
- if (minDate.HasValue)
- {
- statement.TryBind("@DateCreated", minDate.Value.ToDateTimeParamValue());
- }
-
- result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
- }
- },
- ReadTransactionMode);
-
- result.Items = list;
- return result;
- }
-
- private static ActivityLogEntry GetEntry(IReadOnlyList<IResultSetValue> reader)
- {
- var index = 0;
-
- var info = new ActivityLogEntry
- {
- Id = reader[index].ToInt64()
- };
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Name = reader[index].ToString();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Overview = reader[index].ToString();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.ShortOverview = reader[index].ToString();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Type = reader[index].ToString();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.ItemId = reader[index].ToString();
- }
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.UserId = new Guid(reader[index].ToString());
- }
-
- index++;
- info.Date = reader[index].ReadDateTime();
-
- index++;
- if (reader[index].SQLiteType != SQLiteType.Null)
- {
- info.Severity = Enum.Parse<LogLevel>(reader[index].ToString(), true);
- }
-
- return info;
- }
- }
-}
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index ffc916b98..ddd9c7953 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -22,7 +22,6 @@ using Emby.Dlna.Ssdp;
using Emby.Drawing;
using Emby.Notifications;
using Emby.Photos;
-using Emby.Server.Implementations.Activity;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Channels;
using Emby.Server.Implementations.Collections;
@@ -47,6 +46,8 @@ using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.SocketSharp;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
+using Jellyfin.Server.Implementations;
+using Jellyfin.Server.Implementations.Activity;
using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
@@ -94,7 +95,6 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Updates;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Plugins.TheTvdb;
@@ -103,6 +103,7 @@ using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
@@ -553,6 +554,13 @@ namespace Emby.Server.Implementations
return Logger;
});
+ // TODO: properly set up scoping and switch to AddDbContextPool
+ serviceCollection.AddDbContext<JellyfinDb>(
+ options => options.UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"),
+ ServiceLifetime.Transient);
+
+ serviceCollection.AddSingleton<JellyfinDbProvider>();
+
serviceCollection.AddSingleton(_fileSystemManager);
serviceCollection.AddSingleton<TvdbClientManager>();
@@ -663,7 +671,6 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
- serviceCollection.AddSingleton<IActivityRepository, ActivityRepository>();
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
@@ -696,7 +703,6 @@ namespace Emby.Server.Implementations
((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
- ((ActivityRepository)Resolve<IActivityRepository>()).Initialize();
SetStaticProperties();
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 44fc932e3..dccbe2a9a 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
<PropertyGroup>
@@ -9,6 +9,7 @@
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
<ProjectReference Include="..\Emby.Notifications\Emby.Notifications.csproj" />
<ProjectReference Include="..\Jellyfin.Api\Jellyfin.Api.csproj" />
+ <ProjectReference Include="..\Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj" />
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
@@ -50,7 +51,7 @@
</ItemGroup>
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
diff --git a/Jellyfin.Data/DbContexts/Jellyfin.cs b/Jellyfin.Data/DbContexts/Jellyfin.cs
deleted file mode 100644
index fd488ce7d..000000000
--- a/Jellyfin.Data/DbContexts/Jellyfin.cs
+++ /dev/null
@@ -1,1140 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-// This code was generated from a template.
-//
-// Manual changes to this file may cause unexpected behavior in your application.
-// Manual changes to this file will be overwritten if the code is regenerated.
-//
-// Produced by Entity Framework Visual Editor
-// https://github.com/msawczyn/EFDesigner
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.ComponentModel.DataAnnotations.Schema;
-using Microsoft.EntityFrameworkCore;
-
-namespace Jellyfin.Data.DbContexts
-{
- /// <inheritdoc/>
- public partial class Jellyfin : DbContext
- {
- #region DbSets
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Artwork> Artwork { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Book> Books { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.BookMetadata> BookMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Chapter> Chapters { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Collection> Collections { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.CollectionItem> CollectionItems { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Company> Companies { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.CompanyMetadata> CompanyMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.CustomItem> CustomItems { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.CustomItemMetadata> CustomItemMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Episode> Episodes { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.EpisodeMetadata> EpisodeMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Genre> Genres { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Group> Groups { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Library> Libraries { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.LibraryItem> LibraryItems { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.LibraryRoot> LibraryRoot { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MediaFile> MediaFiles { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MediaFileStream> MediaFileStream { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Metadata> Metadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MetadataProvider> MetadataProviders { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MetadataProviderId> MetadataProviderIds { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Movie> Movies { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MovieMetadata> MovieMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MusicAlbum> MusicAlbums { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.MusicAlbumMetadata> MusicAlbumMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Permission> Permissions { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Person> People { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.PersonRole> PersonRoles { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Photo> Photo { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.PhotoMetadata> PhotoMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Preference> Preferences { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.ProviderMapping> ProviderMappings { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Rating> Ratings { get; set; }
-
- /// <summary>
- /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to
- /// store review ratings, not age ratings
- /// </summary>
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.RatingSource> RatingSources { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Release> Releases { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Season> Seasons { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.SeasonMetadata> SeasonMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Series> Series { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.SeriesMetadata> SeriesMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.Track> Tracks { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.TrackMetadata> TrackMetadata { get; set; }
- public virtual Microsoft.EntityFrameworkCore.DbSet<global::Jellyfin.Data.Entities.User> Users { get; set; }
- #endregion DbSets
-
- /// <summary>
- /// Default connection string
- /// </summary>
- public static string ConnectionString { get; set; } = @"Data Source=jellyfin.db";
-
- /// <inheritdoc />
- public Jellyfin(DbContextOptions<Jellyfin> options) : base(options)
- {
- }
-
- partial void CustomInit(DbContextOptionsBuilder optionsBuilder);
-
- /// <inheritdoc />
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
- {
- CustomInit(optionsBuilder);
- }
-
- partial void OnModelCreatingImpl(ModelBuilder modelBuilder);
- partial void OnModelCreatedImpl(ModelBuilder modelBuilder);
-
- /// <inheritdoc />
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- base.OnModelCreating(modelBuilder);
- OnModelCreatingImpl(modelBuilder);
-
- modelBuilder.HasDefaultSchema("jellyfin");
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>()
- .ToTable("Artwork")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>()
- .Property(t => t.Path)
- .HasMaxLength(65535)
- .IsRequired()
- .HasField("_Path")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>()
- .Property(t => t.Kind)
- .IsRequired()
- .HasField("_Kind")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>().HasIndex(t => t.Kind);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Artwork>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Book>()
- .HasMany(x => x.BookMetadata)
- .WithOne()
- .HasForeignKey("BookMetadata_BookMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Book>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.BookMetadata>()
- .Property(t => t.ISBN)
- .HasField("_ISBN")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.BookMetadata>()
- .HasMany(x => x.Publishers)
- .WithOne()
- .HasForeignKey("Company_Publishers_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .ToTable("Chapter")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.Language)
- .HasMaxLength(3)
- .IsRequired()
- .HasField("_Language")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.TimeStart)
- .IsRequired()
- .HasField("_TimeStart")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.TimeEnd)
- .HasField("_TimeEnd")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Chapter>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Collection>()
- .ToTable("Collection")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Collection>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Collection>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Collection>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Collection>()
- .HasMany(x => x.CollectionItem)
- .WithOne()
- .HasForeignKey("CollectionItem_CollectionItem_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .ToTable("CollectionItem")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .HasOne(x => x.LibraryItem)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.CollectionItem>("LibraryItem_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .HasOne(x => x.Next)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.CollectionItem>("CollectionItem_Next_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CollectionItem>()
- .HasOne(x => x.Previous)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.CollectionItem>("CollectionItem_Previous_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Company>()
- .ToTable("Company")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Company>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Company>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Company>()
- .HasMany(x => x.CompanyMetadata)
- .WithOne()
- .HasForeignKey("CompanyMetadata_CompanyMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Company>()
- .HasOne(x => x.Parent)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.Company>("Company_Parent_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CompanyMetadata>()
- .Property(t => t.Description)
- .HasMaxLength(65535)
- .HasField("_Description")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CompanyMetadata>()
- .Property(t => t.Headquarters)
- .HasMaxLength(255)
- .HasField("_Headquarters")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CompanyMetadata>()
- .Property(t => t.Country)
- .HasMaxLength(2)
- .HasField("_Country")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CompanyMetadata>()
- .Property(t => t.Homepage)
- .HasMaxLength(1024)
- .HasField("_Homepage")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CustomItem>()
- .HasMany(x => x.CustomItemMetadata)
- .WithOne()
- .HasForeignKey("CustomItemMetadata_CustomItemMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.CustomItem>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
-
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Episode>()
- .Property(t => t.EpisodeNumber)
- .HasField("_EpisodeNumber")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Episode>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Episode>()
- .HasMany(x => x.EpisodeMetadata)
- .WithOne()
- .HasForeignKey("EpisodeMetadata_EpisodeMetadata_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.EpisodeMetadata>()
- .Property(t => t.Outline)
- .HasMaxLength(1024)
- .HasField("_Outline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.EpisodeMetadata>()
- .Property(t => t.Plot)
- .HasMaxLength(65535)
- .HasField("_Plot")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.EpisodeMetadata>()
- .Property(t => t.Tagline)
- .HasMaxLength(1024)
- .HasField("_Tagline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Genre>()
- .ToTable("Genre")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Genre>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Genre>()
- .Property(t => t.Name)
- .HasMaxLength(255)
- .IsRequired()
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Genre>().HasIndex(t => t.Name)
- .IsUnique();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Genre>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .ToTable("Groups")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .Property(t => t.Id)
- .IsRequired()
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .Property(t => t.Name)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>().Property<byte[]>("Timestamp").IsConcurrencyToken();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .HasMany(x => x.GroupPermissions)
- .WithOne()
- .HasForeignKey("Permission_GroupPermissions_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .HasMany(x => x.ProviderMappings)
- .WithOne()
- .HasForeignKey("ProviderMapping_ProviderMappings_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Group>()
- .HasMany(x => x.Preferences)
- .WithOne()
- .HasForeignKey("Preference_Preferences_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Library>()
- .ToTable("Library")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Library>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Library>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .IsRequired()
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Library>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .ToTable("LibraryItem")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .Property(t => t.UrlId)
- .IsRequired()
- .HasField("_UrlId")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>().HasIndex(t => t.UrlId)
- .IsUnique();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .Property(t => t.DateAdded)
- .IsRequired()
- .HasField("_DateAdded")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryItem>()
- .HasOne(x => x.LibraryRoot)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.LibraryItem>("LibraryRoot_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .ToTable("LibraryRoot")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .Property(t => t.Path)
- .HasMaxLength(65535)
- .IsRequired()
- .HasField("_Path")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .Property(t => t.NetworkPath)
- .HasMaxLength(65535)
- .HasField("_NetworkPath")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.LibraryRoot>()
- .HasOne(x => x.Library)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.LibraryRoot>("Library_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .ToTable("MediaFile")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .Property(t => t.Path)
- .HasMaxLength(65535)
- .IsRequired()
- .HasField("_Path")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .Property(t => t.Kind)
- .IsRequired()
- .HasField("_Kind")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFile>()
- .HasMany(x => x.MediaFileStreams)
- .WithOne()
- .HasForeignKey("MediaFileStream_MediaFileStreams_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFileStream>()
- .ToTable("MediaFileStream")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFileStream>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFileStream>()
- .Property(t => t.StreamNumber)
- .IsRequired()
- .HasField("_StreamNumber")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MediaFileStream>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .ToTable("Metadata")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.Title)
- .HasMaxLength(1024)
- .IsRequired()
- .HasField("_Title")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.OriginalTitle)
- .HasMaxLength(1024)
- .HasField("_OriginalTitle")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.SortTitle)
- .HasMaxLength(1024)
- .HasField("_SortTitle")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.Language)
- .HasMaxLength(3)
- .IsRequired()
- .HasField("_Language")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.ReleaseDate)
- .HasField("_ReleaseDate")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.DateAdded)
- .IsRequired()
- .HasField("_DateAdded")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.DateModified)
- .IsRequired()
- .HasField("_DateModified")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .HasMany(x => x.PersonRoles)
- .WithOne()
- .HasForeignKey("PersonRole_PersonRoles_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .HasMany(x => x.Genres)
- .WithOne()
- .HasForeignKey("Genre_Genres_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .HasMany(x => x.Artwork)
- .WithOne()
- .HasForeignKey("Artwork_Artwork_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .HasMany(x => x.Ratings)
- .WithOne()
- .HasForeignKey("Rating_Ratings_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Metadata>()
- .HasMany(x => x.Sources)
- .WithOne()
- .HasForeignKey("MetadataProviderId_Sources_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProvider>()
- .ToTable("MetadataProvider")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProvider>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProvider>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .IsRequired()
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProvider>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProviderId>()
- .ToTable("MetadataProviderId")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProviderId>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProviderId>()
- .Property(t => t.ProviderId)
- .HasMaxLength(255)
- .IsRequired()
- .HasField("_ProviderId")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProviderId>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MetadataProviderId>()
- .HasOne(x => x.MetadataProvider)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.MetadataProviderId>("MetadataProvider_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Movie>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Movie>()
- .HasMany(x => x.MovieMetadata)
- .WithOne()
- .HasForeignKey("MovieMetadata_MovieMetadata_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MovieMetadata>()
- .Property(t => t.Outline)
- .HasMaxLength(1024)
- .HasField("_Outline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MovieMetadata>()
- .Property(t => t.Plot)
- .HasMaxLength(65535)
- .HasField("_Plot")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MovieMetadata>()
- .Property(t => t.Tagline)
- .HasMaxLength(1024)
- .HasField("_Tagline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MovieMetadata>()
- .Property(t => t.Country)
- .HasMaxLength(2)
- .HasField("_Country")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MovieMetadata>()
- .HasMany(x => x.Studios)
- .WithOne()
- .HasForeignKey("Company_Studios_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbum>()
- .HasMany(x => x.MusicAlbumMetadata)
- .WithOne()
- .HasForeignKey("MusicAlbumMetadata_MusicAlbumMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbum>()
- .HasMany(x => x.Tracks)
- .WithOne()
- .HasForeignKey("Track_Tracks_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbumMetadata>()
- .Property(t => t.Barcode)
- .HasMaxLength(255)
- .HasField("_Barcode")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbumMetadata>()
- .Property(t => t.LabelNumber)
- .HasMaxLength(255)
- .HasField("_LabelNumber")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbumMetadata>()
- .Property(t => t.Country)
- .HasMaxLength(2)
- .HasField("_Country")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.MusicAlbumMetadata>()
- .HasMany(x => x.Labels)
- .WithOne()
- .HasForeignKey("Company_Labels_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Permission>()
- .ToTable("Permissions")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Permission>()
- .Property(t => t.Id)
- .IsRequired()
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Permission>()
- .Property(t => t.Kind)
- .IsRequired()
- .HasField("_Kind")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Permission>()
- .Property(t => t.Value)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Permission>().Property<byte[]>("Timestamp").IsConcurrencyToken();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .ToTable("Person")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.UrlId)
- .IsRequired()
- .HasField("_UrlId")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .IsRequired()
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.SourceId)
- .HasMaxLength(255)
- .HasField("_SourceId")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.DateAdded)
- .IsRequired()
- .HasField("_DateAdded")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.DateModified)
- .IsRequired()
- .HasField("_DateModified")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Person>()
- .HasMany(x => x.Sources)
- .WithOne()
- .HasForeignKey("MetadataProviderId_Sources_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .ToTable("PersonRole")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .Property(t => t.Role)
- .HasMaxLength(1024)
- .HasField("_Role")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .Property(t => t.Type)
- .IsRequired()
- .HasField("_Type")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .HasOne(x => x.Person)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.PersonRole>("Person_Id")
- .IsRequired()
- .OnDelete(DeleteBehavior.Cascade);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .HasOne(x => x.Artwork)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.PersonRole>("Artwork_Artwork_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.PersonRole>()
- .HasMany(x => x.Sources)
- .WithOne()
- .HasForeignKey("MetadataProviderId_Sources_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Photo>()
- .HasMany(x => x.PhotoMetadata)
- .WithOne()
- .HasForeignKey("PhotoMetadata_PhotoMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Photo>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
-
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Preference>()
- .ToTable("Preferences")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Preference>()
- .Property(t => t.Id)
- .IsRequired()
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Preference>()
- .Property(t => t.Kind)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Preference>()
- .Property(t => t.Value)
- .HasMaxLength(65535)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Preference>().Property<byte[]>("Timestamp").IsConcurrencyToken();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>()
- .ToTable("ProviderMappings")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>()
- .Property(t => t.Id)
- .IsRequired()
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>()
- .Property(t => t.ProviderName)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>()
- .Property(t => t.ProviderSecrets)
- .HasMaxLength(65535)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>()
- .Property(t => t.ProviderData)
- .HasMaxLength(65535)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.ProviderMapping>().Property<byte[]>("Timestamp").IsConcurrencyToken();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .ToTable("Rating")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .Property(t => t.Value)
- .IsRequired()
- .HasField("_Value")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .Property(t => t.Votes)
- .HasField("_Votes")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Rating>()
- .HasOne(x => x.RatingType)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.Rating>("RatingSource_RatingType_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .ToTable("RatingType")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .Property(t => t.MaximumValue)
- .IsRequired()
- .HasField("_MaximumValue")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .Property(t => t.MinimumValue)
- .IsRequired()
- .HasField("_MinimumValue")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.RatingSource>()
- .HasOne(x => x.Source)
- .WithOne()
- .HasForeignKey<global::Jellyfin.Data.Entities.RatingSource>("MetadataProviderId_Source_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .ToTable("Release")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .Property(t => t.Id)
- .IsRequired()
- .HasField("_Id")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .Property(t => t.Name)
- .HasMaxLength(1024)
- .IsRequired()
- .HasField("_Name")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .Property(t => t.Timestamp)
- .IsRequired()
- .HasField("_Timestamp")
- .UsePropertyAccessMode(PropertyAccessMode.Property)
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .HasMany(x => x.MediaFiles)
- .WithOne()
- .HasForeignKey("MediaFile_MediaFiles_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Release>()
- .HasMany(x => x.Chapters)
- .WithOne()
- .HasForeignKey("Chapter_Chapters_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Season>()
- .Property(t => t.SeasonNumber)
- .HasField("_SeasonNumber")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Season>()
- .HasMany(x => x.SeasonMetadata)
- .WithOne()
- .HasForeignKey("SeasonMetadata_SeasonMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Season>()
- .HasMany(x => x.Episodes)
- .WithOne()
- .HasForeignKey("Episode_Episodes_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeasonMetadata>()
- .Property(t => t.Outline)
- .HasMaxLength(1024)
- .HasField("_Outline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Series>()
- .Property(t => t.AirsDayOfWeek)
- .HasField("_AirsDayOfWeek")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Series>()
- .Property(t => t.AirsTime)
- .HasField("_AirsTime")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Series>()
- .Property(t => t.FirstAired)
- .HasField("_FirstAired")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Series>()
- .HasMany(x => x.SeriesMetadata)
- .WithOne()
- .HasForeignKey("SeriesMetadata_SeriesMetadata_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Series>()
- .HasMany(x => x.Seasons)
- .WithOne()
- .HasForeignKey("Season_Seasons_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeriesMetadata>()
- .Property(t => t.Outline)
- .HasMaxLength(1024)
- .HasField("_Outline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeriesMetadata>()
- .Property(t => t.Plot)
- .HasMaxLength(65535)
- .HasField("_Plot")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeriesMetadata>()
- .Property(t => t.Tagline)
- .HasMaxLength(1024)
- .HasField("_Tagline")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeriesMetadata>()
- .Property(t => t.Country)
- .HasMaxLength(2)
- .HasField("_Country")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.SeriesMetadata>()
- .HasMany(x => x.Networks)
- .WithOne()
- .HasForeignKey("Company_Networks_Id")
- .IsRequired();
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Track>()
- .Property(t => t.TrackNumber)
- .HasField("_TrackNumber")
- .UsePropertyAccessMode(PropertyAccessMode.Property);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Track>()
- .HasMany(x => x.Releases)
- .WithOne()
- .HasForeignKey("Release_Releases_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.Track>()
- .HasMany(x => x.TrackMetadata)
- .WithOne()
- .HasForeignKey("TrackMetadata_TrackMetadata_Id")
- .IsRequired();
-
-
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .ToTable("Users")
- .HasKey(t => t.Id);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.Id)
- .IsRequired()
- .ValueGeneratedOnAdd();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.LastLoginTimestamp)
- .IsRequired()
- .IsRowVersion();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.Username)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.Password)
- .HasMaxLength(65535);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.MustUpdatePassword)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.AudioLanguagePreference)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.AuthenticationProviderId)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.GroupedFolders)
- .HasMaxLength(65535);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.InvalidLoginAttemptCount)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.LatestItemExcludes)
- .HasMaxLength(65535);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.MyMediaExcludes)
- .HasMaxLength(65535);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.OrderedViews)
- .HasMaxLength(65535);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.SubtitleMode)
- .HasMaxLength(255)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.PlayDefaultAudioTrack)
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .Property(t => t.SubtitleLanguagePrefernce)
- .HasMaxLength(255);
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .HasMany(x => x.Groups)
- .WithOne()
- .HasForeignKey("Group_Groups_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .HasMany(x => x.Permissions)
- .WithOne()
- .HasForeignKey("Permission_Permissions_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .HasMany(x => x.ProviderMappings)
- .WithOne()
- .HasForeignKey("ProviderMapping_ProviderMappings_Id")
- .IsRequired();
- modelBuilder.Entity<global::Jellyfin.Data.Entities.User>()
- .HasMany(x => x.Preferences)
- .WithOne()
- .HasForeignKey("Preference_Preferences_Id")
- .IsRequired();
-
- OnModelCreatedImpl(modelBuilder);
- }
- }
-}
diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs
new file mode 100644
index 000000000..633838991
--- /dev/null
+++ b/Jellyfin.Data/Entities/ActivityLog.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace Jellyfin.Data.Entities
+{
+ [Table("ActivityLog")]
+ public partial class ActivityLog
+ {
+ partial void Init();
+
+ /// <summary>
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// </summary>
+ protected ActivityLog()
+ {
+ Init();
+ }
+
+ /// <summary>
+ /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
+ /// </summary>
+ public static ActivityLog CreateActivityLogUnsafe()
+ {
+ return new ActivityLog();
+ }
+
+ /// <summary>
+ /// Public constructor with required data
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="type"></param>
+ /// <param name="userid"></param>
+ /// <param name="datecreated"></param>
+ /// <param name="logseverity"></param>
+ public ActivityLog(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity)
+ {
+ if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
+ this.Name = name;
+
+ if (string.IsNullOrEmpty(type)) throw new ArgumentNullException(nameof(type));
+ this.Type = type;
+
+ this.UserId = userid;
+
+ this.DateCreated = datecreated;
+
+ this.LogSeverity = logseverity;
+
+
+ Init();
+ }
+
+ /// <summary>
+ /// Static create function (for use in LINQ queries, etc.)
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="type"></param>
+ /// <param name="userid"></param>
+ /// <param name="datecreated"></param>
+ /// <param name="logseverity"></param>
+ public static ActivityLog Create(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity)
+ {
+ return new ActivityLog(name, type, userid, datecreated, logseverity);
+ }
+
+ /*************************************************************************
+ * Properties
+ *************************************************************************/
+
+ /// <summary>
+ /// Identity, Indexed, Required
+ /// </summary>
+ [Key]
+ [Required]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ public int Id { get; protected set; }
+
+ /// <summary>
+ /// Required, Max length = 512
+ /// </summary>
+ [Required]
+ [MaxLength(512)]
+ [StringLength(512)]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Max length = 512
+ /// </summary>
+ [MaxLength(512)]
+ [StringLength(512)]
+ public string Overview { get; set; }
+
+ /// <summary>
+ /// Max length = 512
+ /// </summary>
+ [MaxLength(512)]
+ [StringLength(512)]
+ public string ShortOverview { get; set; }
+
+ /// <summary>
+ /// Required, Max length = 256
+ /// </summary>
+ [Required]
+ [MaxLength(256)]
+ [StringLength(256)]
+ public string Type { get; set; }
+
+ /// <summary>
+ /// Required
+ /// </summary>
+ [Required]
+ public Guid UserId { get; set; }
+
+ /// <summary>
+ /// Max length = 256
+ /// </summary>
+ [MaxLength(256)]
+ [StringLength(256)]
+ public string ItemId { get; set; }
+
+ /// <summary>
+ /// Required
+ /// </summary>
+ [Required]
+ public DateTime DateCreated { get; set; }
+
+ /// <summary>
+ /// Required
+ /// </summary>
+ [Required]
+ public Microsoft.Extensions.Logging.LogLevel LogSeverity { get; set; }
+
+ /// <summary>
+ /// Required, ConcurrenyToken
+ /// </summary>
+ [ConcurrencyCheck]
+ [Required]
+ public uint RowVersion { get; set; }
+
+ public void OnSavingChanges()
+ {
+ RowVersion++;
+ }
+
+ }
+}
+
diff --git a/Jellyfin.Data/ISavingChanges.cs b/Jellyfin.Data/ISavingChanges.cs
new file mode 100644
index 000000000..5388b921d
--- /dev/null
+++ b/Jellyfin.Data/ISavingChanges.cs
@@ -0,0 +1,9 @@
+#pragma warning disable CS1591
+
+namespace Jellyfin.Data
+{
+ public interface ISavingChanges
+ {
+ void OnSavingChanges();
+ }
+}
diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj
index 73ea593b0..8eae366ba 100644
--- a/Jellyfin.Data/Jellyfin.Data.csproj
+++ b/Jellyfin.Data/Jellyfin.Data.csproj
@@ -1,12 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.0</TargetFramework>
+ <TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
+ <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+ <!-- Code analysers-->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
<ItemGroup>
- <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.4" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.3" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
</ItemGroup>
</Project>
diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
new file mode 100644
index 000000000..d7bbf793c
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Querying;
+
+namespace Jellyfin.Server.Implementations.Activity
+{
+ /// <summary>
+ /// Manages the storage and retrieval of <see cref="ActivityLog"/> instances.
+ /// </summary>
+ public class ActivityManager : IActivityManager
+ {
+ private JellyfinDbProvider _provider;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ActivityManager"/> class.
+ /// </summary>
+ /// <param name="provider">The Jellyfin database provider.</param>
+ public ActivityManager(JellyfinDbProvider provider)
+ {
+ _provider = provider;
+ }
+
+ /// <inheritdoc/>
+ public event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
+
+ /// <inheritdoc/>
+ public void Create(ActivityLog entry)
+ {
+ using var dbContext = _provider.CreateContext();
+ dbContext.ActivityLogs.Add(entry);
+ dbContext.SaveChanges();
+
+ EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(ConvertToOldModel(entry)));
+ }
+
+ /// <inheritdoc/>
+ public async Task CreateAsync(ActivityLog entry)
+ {
+ using var dbContext = _provider.CreateContext();
+ await dbContext.ActivityLogs.AddAsync(entry);
+ await dbContext.SaveChangesAsync().ConfigureAwait(false);
+
+ EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(ConvertToOldModel(entry)));
+ }
+
+ /// <inheritdoc/>
+ public QueryResult<ActivityLogEntry> GetPagedResult(
+ Func<IQueryable<ActivityLog>, IEnumerable<ActivityLog>> func,
+ int? startIndex,
+ int? limit)
+ {
+ using var dbContext = _provider.CreateContext();
+
+ var result = func.Invoke(dbContext.ActivityLogs).AsQueryable();
+
+ if (startIndex.HasValue)
+ {
+ result = result.Where(entry => entry.Id >= startIndex.Value);
+ }
+
+ if (limit.HasValue)
+ {
+ result = result.OrderByDescending(entry => entry.DateCreated).Take(limit.Value);
+ }
+
+ // This converts the objects from the new database model to the old for compatibility with the existing API.
+ var list = result.Select(entry => ConvertToOldModel(entry)).ToList();
+
+ return new QueryResult<ActivityLogEntry>()
+ {
+ Items = list,
+ TotalRecordCount = list.Count
+ };
+ }
+
+ /// <inheritdoc/>
+ public QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit)
+ {
+ return GetPagedResult(logs => logs, startIndex, limit);
+ }
+
+ private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
+ {
+ return new ActivityLogEntry
+ {
+ Id = entry.Id,
+ Name = entry.Name,
+ Overview = entry.Overview,
+ ShortOverview = entry.ShortOverview,
+ Type = entry.Type,
+ ItemId = entry.ItemId,
+ UserId = entry.UserId,
+ Date = entry.DateCreated,
+ Severity = entry.LogSeverity
+ };
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
new file mode 100644
index 000000000..a31f28f64
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
@@ -0,0 +1,34 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netcoreapp3.1</TargetFramework>
+ <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+ <!-- Code analysers-->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="..\SharedVersion.cs" />
+ <Compile Remove="Migrations\20200430214405_InitialSchema.cs" />
+ <Compile Remove="Migrations\20200430214405_InitialSchema.Designer.cs" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Jellyfin.Data\Jellyfin.Data.csproj" />
+ <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
+ <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs
new file mode 100644
index 000000000..9c1a23877
--- /dev/null
+++ b/Jellyfin.Server.Implementations/JellyfinDb.cs
@@ -0,0 +1,119 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1201 // Constuctors should not follow properties
+#pragma warning disable SA1516 // Elements should be followed by a blank line
+#pragma warning disable SA1623 // Property's documentation should begin with gets or sets
+#pragma warning disable SA1629 // Documentation should end with a period
+#pragma warning disable SA1648 // Inheritdoc should be used with inheriting class
+
+using System.Linq;
+using Jellyfin.Data;
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+
+namespace Jellyfin.Server.Implementations
+{
+ /// <inheritdoc/>
+ public partial class JellyfinDb : DbContext
+ {
+ public virtual DbSet<ActivityLog> ActivityLogs { get; set; }
+ public virtual DbSet<Artwork> Artwork { get; set; }
+ public virtual DbSet<Book> Books { get; set; }
+ public virtual DbSet<BookMetadata> BookMetadata { get; set; }
+ public virtual DbSet<Chapter> Chapters { get; set; }
+ public virtual DbSet<Collection> Collections { get; set; }
+ public virtual DbSet<CollectionItem> CollectionItems { get; set; }
+ public virtual DbSet<Company> Companies { get; set; }
+ public virtual DbSet<CompanyMetadata> CompanyMetadata { get; set; }
+ public virtual DbSet<CustomItem> CustomItems { get; set; }
+ public virtual DbSet<CustomItemMetadata> CustomItemMetadata { get; set; }
+ public virtual DbSet<Episode> Episodes { get; set; }
+ public virtual DbSet<EpisodeMetadata> EpisodeMetadata { get; set; }
+ public virtual DbSet<Genre> Genres { get; set; }
+ public virtual DbSet<Group> Groups { get; set; }
+ public virtual DbSet<Library> Libraries { get; set; }
+ public virtual DbSet<LibraryItem> LibraryItems { get; set; }
+ public virtual DbSet<LibraryRoot> LibraryRoot { get; set; }
+ public virtual DbSet<MediaFile> MediaFiles { get; set; }
+ public virtual DbSet<MediaFileStream> MediaFileStream { get; set; }
+ public virtual DbSet<Metadata> Metadata { get; set; }
+ public virtual DbSet<MetadataProvider> MetadataProviders { get; set; }
+ public virtual DbSet<MetadataProviderId> MetadataProviderIds { get; set; }
+ public virtual DbSet<Movie> Movies { get; set; }
+ public virtual DbSet<MovieMetadata> MovieMetadata { get; set; }
+ public virtual DbSet<MusicAlbum> MusicAlbums { get; set; }
+ public virtual DbSet<MusicAlbumMetadata> MusicAlbumMetadata { get; set; }
+ public virtual DbSet<Permission> Permissions { get; set; }
+ public virtual DbSet<Person> People { get; set; }
+ public virtual DbSet<PersonRole> PersonRoles { get; set; }
+ public virtual DbSet<Photo> Photo { get; set; }
+ public virtual DbSet<PhotoMetadata> PhotoMetadata { get; set; }
+ public virtual DbSet<Preference> Preferences { get; set; }
+ public virtual DbSet<ProviderMapping> ProviderMappings { get; set; }
+ public virtual DbSet<Rating> Ratings { get; set; }
+
+ /// <summary>
+ /// Repository for global::Jellyfin.Data.Entities.RatingSource - This is the entity to
+ /// store review ratings, not age ratings
+ /// </summary>
+ public virtual DbSet<RatingSource> RatingSources { get; set; }
+ public virtual DbSet<Release> Releases { get; set; }
+ public virtual DbSet<Season> Seasons { get; set; }
+ public virtual DbSet<SeasonMetadata> SeasonMetadata { get; set; }
+ public virtual DbSet<Series> Series { get; set; }
+ public virtual DbSet<SeriesMetadata> SeriesMetadata { get; set; }
+ public virtual DbSet<Track> Tracks { get; set; }
+ public virtual DbSet<TrackMetadata> TrackMetadata { get; set; }
+ public virtual DbSet<User> Users { get; set; }
+
+ /// <summary>
+ /// Gets or sets the default connection string.
+ /// </summary>
+ public static string ConnectionString { get; set; } = @"Data Source=jellyfin.db";
+
+ /// <inheritdoc />
+ public JellyfinDb(DbContextOptions<JellyfinDb> options) : base(options)
+ {
+ }
+
+ partial void CustomInit(DbContextOptionsBuilder optionsBuilder);
+
+ /// <inheritdoc />
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ CustomInit(optionsBuilder);
+ }
+
+ partial void OnModelCreatingImpl(ModelBuilder modelBuilder);
+ partial void OnModelCreatedImpl(ModelBuilder modelBuilder);
+
+ /// <inheritdoc />
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+ OnModelCreatingImpl(modelBuilder);
+
+ modelBuilder.HasDefaultSchema("jellyfin");
+
+ modelBuilder.Entity<Artwork>().HasIndex(t => t.Kind);
+
+ modelBuilder.Entity<Genre>().HasIndex(t => t.Name)
+ .IsUnique();
+
+ modelBuilder.Entity<LibraryItem>().HasIndex(t => t.UrlId)
+ .IsUnique();
+
+ OnModelCreatedImpl(modelBuilder);
+ }
+
+ public override int SaveChanges()
+ {
+ foreach (var entity in ChangeTracker.Entries().Where(e => e.State == EntityState.Modified))
+ {
+ var saveEntity = entity.Entity as ISavingChanges;
+ saveEntity.OnSavingChanges();
+ }
+
+ return base.SaveChanges();
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/JellyfinDbProvider.cs b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs
new file mode 100644
index 000000000..8fdeab088
--- /dev/null
+++ b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs
@@ -0,0 +1,33 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Jellyfin.Server.Implementations
+{
+ /// <summary>
+ /// Factory class for generating new <see cref="JellyfinDb"/> instances.
+ /// </summary>
+ public class JellyfinDbProvider
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="JellyfinDbProvider"/> class.
+ /// </summary>
+ /// <param name="serviceProvider">The application's service provider.</param>
+ public JellyfinDbProvider(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ serviceProvider.GetService<JellyfinDb>().Database.Migrate();
+ }
+
+ /// <summary>
+ /// Creates a new <see cref="JellyfinDb"/> context.
+ /// </summary>
+ /// <returns>The newly created context.</returns>
+ public JellyfinDb CreateContext()
+ {
+ return _serviceProvider.GetService<JellyfinDb>();
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.Designer.cs
new file mode 100644
index 000000000..3fb0fd51e
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.Designer.cs
@@ -0,0 +1,1513 @@
+#pragma warning disable CS1591
+
+// <auto-generated />
+using System;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ [DbContext(typeof(JellyfinDb))]
+ [Migration("20200430215054_InitialSchema")]
+ partial class InitialSchema
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("jellyfin")
+ .HasAnnotation("ProductVersion", "3.1.3");
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateCreated")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ItemId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<int>("LogSeverity")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Overview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ShortOverview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ActivityLog");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Artwork", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Kind");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("Artwork");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Chapter_Chapters_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(3);
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<long?>("TimeEnd")
+ .HasColumnType("INTEGER");
+
+ b.Property<long>("TimeStart")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Chapter_Chapters_Id");
+
+ b.ToTable("Chapter");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Collection", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Collection");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CollectionItem", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_CollectionItem_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_Next_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_Previous_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("LibraryItem_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CollectionItem_CollectionItem_Id");
+
+ b.HasIndex("CollectionItem_Next_Id");
+
+ b.HasIndex("CollectionItem_Previous_Id");
+
+ b.HasIndex("LibraryItem_Id");
+
+ b.ToTable("CollectionItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Company", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Labels_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Networks_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Parent_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Publishers_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Studios_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Company_Labels_Id");
+
+ b.HasIndex("Company_Networks_Id");
+
+ b.HasIndex("Company_Parent_Id");
+
+ b.HasIndex("Company_Publishers_Id");
+
+ b.HasIndex("Company_Studios_Id");
+
+ b.ToTable("Company");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Genre", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("Genre");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Group", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Group_Groups_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Group_Groups_Id");
+
+ b.ToTable("Group");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Library", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Library");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryItem", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("LibraryRoot_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("UrlId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("LibraryRoot_Id");
+
+ b.HasIndex("UrlId")
+ .IsUnique();
+
+ b.ToTable("LibraryItem");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("LibraryItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryRoot", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Library_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("NetworkPath")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Library_Id");
+
+ b.ToTable("LibraryRoot");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFile", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MediaFile_MediaFiles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MediaFile_MediaFiles_Id");
+
+ b.ToTable("MediaFile");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFileStream", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MediaFileStream_MediaFileStreams_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("StreamNumber")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MediaFileStream_MediaFileStreams_Id");
+
+ b.ToTable("MediaFileStream");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Metadata", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("DateModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(3);
+
+ b.Property<string>("OriginalTitle")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<DateTimeOffset?>("ReleaseDate")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SortTitle")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Title")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasKey("Id");
+
+ b.ToTable("Metadata");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("Metadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProvider", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("MetadataProvider");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProviderId", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MetadataProviderId_Sources_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MetadataProvider_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MetadataProviderId_Sources_Id");
+
+ b.HasIndex("MetadataProvider_Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("MetadataProviderId");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Permission_GroupPermissions_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Permission_Permissions_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("Value")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Permission_GroupPermissions_Id");
+
+ b.HasIndex("Permission_Permissions_Id");
+
+ b.ToTable("Permission");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Person", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("DateModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SourceId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<Guid>("UrlId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("Person");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PersonRole", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Artwork_Artwork_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Person_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Role")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Artwork_Artwork_Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.HasIndex("Person_Id");
+
+ b.ToTable("PersonRole");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Preference_Preferences_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Preference_Preferences_Id");
+
+ b.ToTable("Preference");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ProviderMapping", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderData")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("ProviderMapping_ProviderMappings_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("ProviderSecrets")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderMapping_ProviderMappings_Id");
+
+ b.ToTable("ProviderMapping");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Rating", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("RatingSource_RatingType_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("Value")
+ .HasColumnType("REAL");
+
+ b.Property<int?>("Votes")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.HasIndex("RatingSource_RatingType_Id");
+
+ b.ToTable("Rating");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.RatingSource", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("MaximumValue")
+ .HasColumnType("REAL");
+
+ b.Property<int?>("MetadataProviderId_Source_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("MinimumValue")
+ .HasColumnType("REAL");
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MetadataProviderId_Source_Id");
+
+ b.ToTable("RatingSource");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Release", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<int?>("Release_Releases_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Release_Releases_Id");
+
+ b.ToTable("Release");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("AudioLanguagePreference")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("AuthenticationProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool?>("DisplayCollectionsView")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("DisplayMissingEpisodes")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("EnableNextEpisodeAutoPlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("EnableUserPreferenceAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("GroupedFolders")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool?>("HidePlayedInLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("InvalidLoginAttemptCount")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("LatestItemExcludes")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("LoginAttemptsBeforeLockout")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("MustUpdatePassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("MyMediaExcludes")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("OrderedViews")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Password")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool>("PlayDefaultAudioTrack")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("RememberAudioSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("RememberSubtitleSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SubtitleLanguagePrefernce")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("SubtitleMode")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Username")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.HasKey("Id");
+
+ b.ToTable("User");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Book", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Book");
+
+ b.HasDiscriminator().HasValue("Book");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItem", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("LibraryItem");
+
+ b.HasDiscriminator().HasValue("CustomItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Episode", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("EpisodeNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Episode_Episodes_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Episode_Episodes_Id");
+
+ b.ToTable("Episode");
+
+ b.HasDiscriminator().HasValue("Episode");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Movie", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Movie");
+
+ b.HasDiscriminator().HasValue("Movie");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbum", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("MusicAlbum");
+
+ b.HasDiscriminator().HasValue("MusicAlbum");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Photo", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Photo");
+
+ b.HasDiscriminator().HasValue("Photo");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Season", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("SeasonNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Season_Seasons_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Season_Seasons_Id");
+
+ b.ToTable("Season");
+
+ b.HasDiscriminator().HasValue("Season");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Series", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("AirsDayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTimeOffset?>("AirsTime")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTimeOffset?>("FirstAired")
+ .HasColumnType("TEXT");
+
+ b.ToTable("Series");
+
+ b.HasDiscriminator().HasValue("Series");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Track", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("TrackNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Track_Tracks_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Track_Tracks_Id");
+
+ b.ToTable("Track");
+
+ b.HasDiscriminator().HasValue("Track");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.BookMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("BookMetadata_BookMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<long?>("ISBN")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("BookMetadata_BookMetadata_Id");
+
+ b.ToTable("Metadata");
+
+ b.HasDiscriminator().HasValue("BookMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CompanyMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("CompanyMetadata_CompanyMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("Description")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Headquarters")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Homepage")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("CompanyMetadata_CompanyMetadata_Id");
+
+ b.ToTable("CompanyMetadata");
+
+ b.HasDiscriminator().HasValue("CompanyMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("CustomItemMetadata_CustomItemMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("CustomItemMetadata_CustomItemMetadata_Id");
+
+ b.ToTable("CustomItemMetadata");
+
+ b.HasDiscriminator().HasValue("CustomItemMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.EpisodeMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("EpisodeMetadata_EpisodeMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("EpisodeMetadata_EpisodeMetadata_Id");
+
+ b.ToTable("EpisodeMetadata");
+
+ b.HasDiscriminator().HasValue("EpisodeMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MovieMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Country")
+ .HasColumnName("MovieMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<int?>("MovieMetadata_MovieMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Outline")
+ .HasColumnName("MovieMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnName("MovieMetadata_Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Tagline")
+ .HasColumnName("MovieMetadata_Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("MovieMetadata_MovieMetadata_Id");
+
+ b.ToTable("MovieMetadata");
+
+ b.HasDiscriminator().HasValue("MovieMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbumMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Barcode")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Country")
+ .HasColumnName("MusicAlbumMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("LabelNumber")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int?>("MusicAlbumMetadata_MusicAlbumMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("MusicAlbumMetadata_MusicAlbumMetadata_Id");
+
+ b.ToTable("MusicAlbumMetadata");
+
+ b.HasDiscriminator().HasValue("MusicAlbumMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PhotoMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("PhotoMetadata_PhotoMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("PhotoMetadata_PhotoMetadata_Id");
+
+ b.ToTable("PhotoMetadata");
+
+ b.HasDiscriminator().HasValue("PhotoMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeasonMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Outline")
+ .HasColumnName("SeasonMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<int?>("SeasonMetadata_SeasonMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("SeasonMetadata_SeasonMetadata_Id");
+
+ b.ToTable("SeasonMetadata");
+
+ b.HasDiscriminator().HasValue("SeasonMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeriesMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Country")
+ .HasColumnName("SeriesMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("Outline")
+ .HasColumnName("SeriesMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnName("SeriesMetadata_Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("SeriesMetadata_SeriesMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Tagline")
+ .HasColumnName("SeriesMetadata_Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("SeriesMetadata_SeriesMetadata_Id");
+
+ b.ToTable("SeriesMetadata");
+
+ b.HasDiscriminator().HasValue("SeriesMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.TrackMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("TrackMetadata_TrackMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("TrackMetadata_TrackMetadata_Id");
+
+ b.ToTable("TrackMetadata");
+
+ b.HasDiscriminator().HasValue("TrackMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Artwork", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Artwork")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Release", null)
+ .WithMany("Chapters")
+ .HasForeignKey("Chapter_Chapters_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CollectionItem", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Collection", null)
+ .WithMany("CollectionItem")
+ .HasForeignKey("CollectionItem_CollectionItem_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CollectionItem", "Next")
+ .WithMany()
+ .HasForeignKey("CollectionItem_Next_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CollectionItem", "Previous")
+ .WithMany()
+ .HasForeignKey("CollectionItem_Previous_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.LibraryItem", "LibraryItem")
+ .WithMany()
+ .HasForeignKey("LibraryItem_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Company", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbumMetadata", null)
+ .WithMany("Labels")
+ .HasForeignKey("Company_Labels_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.SeriesMetadata", null)
+ .WithMany("Networks")
+ .HasForeignKey("Company_Networks_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Company", "Parent")
+ .WithMany()
+ .HasForeignKey("Company_Parent_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.BookMetadata", null)
+ .WithMany("Publishers")
+ .HasForeignKey("Company_Publishers_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.MovieMetadata", null)
+ .WithMany("Studios")
+ .HasForeignKey("Company_Studios_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Genre", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Genres")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Group", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Groups")
+ .HasForeignKey("Group_Groups_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryItem", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.LibraryRoot", "LibraryRoot")
+ .WithMany()
+ .HasForeignKey("LibraryRoot_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryRoot", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Library", "Library")
+ .WithMany()
+ .HasForeignKey("Library_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFile", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Release", null)
+ .WithMany("MediaFiles")
+ .HasForeignKey("MediaFile_MediaFiles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFileStream", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MediaFile", null)
+ .WithMany("MediaFileStreams")
+ .HasForeignKey("MediaFileStream_MediaFileStreams_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProviderId", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Person", null)
+ .WithMany("Sources")
+ .HasForeignKey("MetadataProviderId_Sources_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.PersonRole", null)
+ .WithMany("Sources")
+ .HasForeignKey("MetadataProviderId_Sources_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.MetadataProvider", "MetadataProvider")
+ .WithMany()
+ .HasForeignKey("MetadataProvider_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Sources")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("GroupPermissions")
+ .HasForeignKey("Permission_GroupPermissions_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Permissions")
+ .HasForeignKey("Permission_Permissions_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PersonRole", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Artwork", "Artwork")
+ .WithMany()
+ .HasForeignKey("Artwork_Artwork_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("PersonRoles")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Person", "Person")
+ .WithMany()
+ .HasForeignKey("Person_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ProviderMapping", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("ProviderMappings")
+ .HasForeignKey("ProviderMapping_ProviderMappings_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("ProviderMappings")
+ .HasForeignKey("ProviderMapping_ProviderMappings_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Rating", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Ratings")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.RatingSource", "RatingType")
+ .WithMany()
+ .HasForeignKey("RatingSource_RatingType_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.RatingSource", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MetadataProviderId", "Source")
+ .WithMany()
+ .HasForeignKey("MetadataProviderId_Source_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Release", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Book", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CustomItem", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id1");
+
+ b.HasOne("Jellyfin.Data.Entities.Episode", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id2");
+
+ b.HasOne("Jellyfin.Data.Entities.Movie", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id3");
+
+ b.HasOne("Jellyfin.Data.Entities.Photo", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id4");
+
+ b.HasOne("Jellyfin.Data.Entities.Track", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id5");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Episode", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Season", null)
+ .WithMany("Episodes")
+ .HasForeignKey("Episode_Episodes_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Season", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Series", null)
+ .WithMany("Seasons")
+ .HasForeignKey("Season_Seasons_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Track", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbum", null)
+ .WithMany("Tracks")
+ .HasForeignKey("Track_Tracks_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.BookMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Book", null)
+ .WithMany("BookMetadata")
+ .HasForeignKey("BookMetadata_BookMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CompanyMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Company", null)
+ .WithMany("CompanyMetadata")
+ .HasForeignKey("CompanyMetadata_CompanyMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.CustomItem", null)
+ .WithMany("CustomItemMetadata")
+ .HasForeignKey("CustomItemMetadata_CustomItemMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.EpisodeMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Episode", null)
+ .WithMany("EpisodeMetadata")
+ .HasForeignKey("EpisodeMetadata_EpisodeMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MovieMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Movie", null)
+ .WithMany("MovieMetadata")
+ .HasForeignKey("MovieMetadata_MovieMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbumMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbum", null)
+ .WithMany("MusicAlbumMetadata")
+ .HasForeignKey("MusicAlbumMetadata_MusicAlbumMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PhotoMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Photo", null)
+ .WithMany("PhotoMetadata")
+ .HasForeignKey("PhotoMetadata_PhotoMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeasonMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Season", null)
+ .WithMany("SeasonMetadata")
+ .HasForeignKey("SeasonMetadata_SeasonMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeriesMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Series", null)
+ .WithMany("SeriesMetadata")
+ .HasForeignKey("SeriesMetadata_SeriesMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.TrackMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Track", null)
+ .WithMany("TrackMetadata")
+ .HasForeignKey("TrackMetadata_TrackMetadata_Id");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.cs b/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.cs
new file mode 100644
index 000000000..f6f2f1a81
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20200430215054_InitialSchema.cs
@@ -0,0 +1,1294 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1601
+
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ public partial class InitialSchema : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.EnsureSchema(
+ name: "jellyfin");
+
+ migrationBuilder.CreateTable(
+ name: "ActivityLog",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 512, nullable: false),
+ Overview = table.Column<string>(maxLength: 512, nullable: true),
+ ShortOverview = table.Column<string>(maxLength: 512, nullable: true),
+ Type = table.Column<string>(maxLength: 256, nullable: false),
+ UserId = table.Column<Guid>(nullable: false),
+ ItemId = table.Column<string>(maxLength: 256, nullable: true),
+ DateCreated = table.Column<DateTime>(nullable: false),
+ LogSeverity = table.Column<int>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ActivityLog", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Collection",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: true),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Collection", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Library",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Library", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "MetadataProvider",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MetadataProvider", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Person",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ UrlId = table.Column<Guid>(nullable: false),
+ Name = table.Column<string>(maxLength: 1024, nullable: false),
+ SourceId = table.Column<string>(maxLength: 255, nullable: true),
+ DateAdded = table.Column<DateTime>(nullable: false),
+ DateModified = table.Column<DateTime>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Person", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "User",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Username = table.Column<string>(maxLength: 255, nullable: false),
+ Password = table.Column<string>(maxLength: 65535, nullable: true),
+ MustUpdatePassword = table.Column<bool>(nullable: false),
+ AudioLanguagePreference = table.Column<string>(maxLength: 255, nullable: false),
+ AuthenticationProviderId = table.Column<string>(maxLength: 255, nullable: false),
+ GroupedFolders = table.Column<string>(maxLength: 65535, nullable: true),
+ InvalidLoginAttemptCount = table.Column<int>(nullable: false),
+ LatestItemExcludes = table.Column<string>(maxLength: 65535, nullable: true),
+ LoginAttemptsBeforeLockout = table.Column<int>(nullable: true),
+ MyMediaExcludes = table.Column<string>(maxLength: 65535, nullable: true),
+ OrderedViews = table.Column<string>(maxLength: 65535, nullable: true),
+ SubtitleMode = table.Column<string>(maxLength: 255, nullable: false),
+ PlayDefaultAudioTrack = table.Column<bool>(nullable: false),
+ SubtitleLanguagePrefernce = table.Column<string>(maxLength: 255, nullable: true),
+ DisplayMissingEpisodes = table.Column<bool>(nullable: true),
+ DisplayCollectionsView = table.Column<bool>(nullable: true),
+ HidePlayedInLatest = table.Column<bool>(nullable: true),
+ RememberAudioSelections = table.Column<bool>(nullable: true),
+ RememberSubtitleSelections = table.Column<bool>(nullable: true),
+ EnableNextEpisodeAutoPlay = table.Column<bool>(nullable: true),
+ EnableUserPreferenceAccess = table.Column<bool>(nullable: true),
+ RowVersion = table.Column<uint>(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_User", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "LibraryRoot",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Path = table.Column<string>(maxLength: 65535, nullable: false),
+ NetworkPath = table.Column<string>(maxLength: 65535, nullable: true),
+ RowVersion = table.Column<uint>(nullable: false),
+ Library_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_LibraryRoot", x => x.Id);
+ table.ForeignKey(
+ name: "FK_LibraryRoot_Library_Library_Id",
+ column: x => x.Library_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Library",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Group",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 255, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Group_Groups_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Group", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Group_User_Group_Groups_Id",
+ column: x => x.Group_Groups_Id,
+ principalSchema: "jellyfin",
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "LibraryItem",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ UrlId = table.Column<Guid>(nullable: false),
+ DateAdded = table.Column<DateTime>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ LibraryRoot_Id = table.Column<int>(nullable: true),
+ Discriminator = table.Column<string>(nullable: false),
+ EpisodeNumber = table.Column<int>(nullable: true),
+ Episode_Episodes_Id = table.Column<int>(nullable: true),
+ SeasonNumber = table.Column<int>(nullable: true),
+ Season_Seasons_Id = table.Column<int>(nullable: true),
+ AirsDayOfWeek = table.Column<int>(nullable: true),
+ AirsTime = table.Column<DateTimeOffset>(nullable: true),
+ FirstAired = table.Column<DateTimeOffset>(nullable: true),
+ TrackNumber = table.Column<int>(nullable: true),
+ Track_Tracks_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_LibraryItem", x => x.Id);
+ table.ForeignKey(
+ name: "FK_LibraryItem_LibraryItem_Episode_Episodes_Id",
+ column: x => x.Episode_Episodes_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_LibraryItem_LibraryRoot_LibraryRoot_Id",
+ column: x => x.LibraryRoot_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryRoot",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_LibraryItem_LibraryItem_Season_Seasons_Id",
+ column: x => x.Season_Seasons_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_LibraryItem_LibraryItem_Track_Tracks_Id",
+ column: x => x.Track_Tracks_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Permission",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Kind = table.Column<int>(nullable: false),
+ Value = table.Column<bool>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Permission_GroupPermissions_Id = table.Column<int>(nullable: true),
+ Permission_Permissions_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Permission", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Permission_Group_Permission_GroupPermissions_Id",
+ column: x => x.Permission_GroupPermissions_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Group",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Permission_User_Permission_Permissions_Id",
+ column: x => x.Permission_Permissions_Id,
+ principalSchema: "jellyfin",
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Preference",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Kind = table.Column<int>(nullable: false),
+ Value = table.Column<string>(maxLength: 65535, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Preference_Preferences_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Preference", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Preference_Group_Preference_Preferences_Id",
+ column: x => x.Preference_Preferences_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Group",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Preference_User_Preference_Preferences_Id",
+ column: x => x.Preference_Preferences_Id,
+ principalSchema: "jellyfin",
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "ProviderMapping",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ ProviderName = table.Column<string>(maxLength: 255, nullable: false),
+ ProviderSecrets = table.Column<string>(maxLength: 65535, nullable: false),
+ ProviderData = table.Column<string>(maxLength: 65535, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ ProviderMapping_ProviderMappings_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ProviderMapping", x => x.Id);
+ table.ForeignKey(
+ name: "FK_ProviderMapping_Group_ProviderMapping_ProviderMappings_Id",
+ column: x => x.ProviderMapping_ProviderMappings_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Group",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_ProviderMapping_User_ProviderMapping_ProviderMappings_Id",
+ column: x => x.ProviderMapping_ProviderMappings_Id,
+ principalSchema: "jellyfin",
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "CollectionItem",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ RowVersion = table.Column<uint>(nullable: false),
+ LibraryItem_Id = table.Column<int>(nullable: true),
+ CollectionItem_Next_Id = table.Column<int>(nullable: true),
+ CollectionItem_Previous_Id = table.Column<int>(nullable: true),
+ CollectionItem_CollectionItem_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_CollectionItem", x => x.Id);
+ table.ForeignKey(
+ name: "FK_CollectionItem_Collection_CollectionItem_CollectionItem_Id",
+ column: x => x.CollectionItem_CollectionItem_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Collection",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_CollectionItem_CollectionItem_CollectionItem_Next_Id",
+ column: x => x.CollectionItem_Next_Id,
+ principalSchema: "jellyfin",
+ principalTable: "CollectionItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_CollectionItem_CollectionItem_CollectionItem_Previous_Id",
+ column: x => x.CollectionItem_Previous_Id,
+ principalSchema: "jellyfin",
+ principalTable: "CollectionItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_CollectionItem_LibraryItem_LibraryItem_Id",
+ column: x => x.LibraryItem_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Release",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Release_Releases_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Release", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id1",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id2",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id3",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id4",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Release_LibraryItem_Release_Releases_Id5",
+ column: x => x.Release_Releases_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Chapter",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: true),
+ Language = table.Column<string>(maxLength: 3, nullable: false),
+ TimeStart = table.Column<long>(nullable: false),
+ TimeEnd = table.Column<long>(nullable: true),
+ RowVersion = table.Column<uint>(nullable: false),
+ Chapter_Chapters_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Chapter", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Chapter_Release_Chapter_Chapters_Id",
+ column: x => x.Chapter_Chapters_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Release",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "MediaFile",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Path = table.Column<string>(maxLength: 65535, nullable: false),
+ Kind = table.Column<int>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ MediaFile_MediaFiles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MediaFile", x => x.Id);
+ table.ForeignKey(
+ name: "FK_MediaFile_Release_MediaFile_MediaFiles_Id",
+ column: x => x.MediaFile_MediaFiles_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Release",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "MediaFileStream",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ StreamNumber = table.Column<int>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ MediaFileStream_MediaFileStreams_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MediaFileStream", x => x.Id);
+ table.ForeignKey(
+ name: "FK_MediaFileStream_MediaFile_MediaFileStream_MediaFileStreams_Id",
+ column: x => x.MediaFileStream_MediaFileStreams_Id,
+ principalSchema: "jellyfin",
+ principalTable: "MediaFile",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "PersonRole",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Role = table.Column<string>(maxLength: 1024, nullable: true),
+ Type = table.Column<int>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Person_Id = table.Column<int>(nullable: true),
+ Artwork_Artwork_Id = table.Column<int>(nullable: true),
+ PersonRole_PersonRoles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_PersonRole", x => x.Id);
+ table.ForeignKey(
+ name: "FK_PersonRole_Person_Person_Id",
+ column: x => x.Person_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Person",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Metadata",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Title = table.Column<string>(maxLength: 1024, nullable: false),
+ OriginalTitle = table.Column<string>(maxLength: 1024, nullable: true),
+ SortTitle = table.Column<string>(maxLength: 1024, nullable: true),
+ Language = table.Column<string>(maxLength: 3, nullable: false),
+ ReleaseDate = table.Column<DateTimeOffset>(nullable: true),
+ DateAdded = table.Column<DateTime>(nullable: false),
+ DateModified = table.Column<DateTime>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ Discriminator = table.Column<string>(nullable: false),
+ ISBN = table.Column<long>(nullable: true),
+ BookMetadata_BookMetadata_Id = table.Column<int>(nullable: true),
+ Description = table.Column<string>(maxLength: 65535, nullable: true),
+ Headquarters = table.Column<string>(maxLength: 255, nullable: true),
+ Country = table.Column<string>(maxLength: 2, nullable: true),
+ Homepage = table.Column<string>(maxLength: 1024, nullable: true),
+ CompanyMetadata_CompanyMetadata_Id = table.Column<int>(nullable: true),
+ CustomItemMetadata_CustomItemMetadata_Id = table.Column<int>(nullable: true),
+ Outline = table.Column<string>(maxLength: 1024, nullable: true),
+ Plot = table.Column<string>(maxLength: 65535, nullable: true),
+ Tagline = table.Column<string>(maxLength: 1024, nullable: true),
+ EpisodeMetadata_EpisodeMetadata_Id = table.Column<int>(nullable: true),
+ MovieMetadata_Outline = table.Column<string>(maxLength: 1024, nullable: true),
+ MovieMetadata_Plot = table.Column<string>(maxLength: 65535, nullable: true),
+ MovieMetadata_Tagline = table.Column<string>(maxLength: 1024, nullable: true),
+ MovieMetadata_Country = table.Column<string>(maxLength: 2, nullable: true),
+ MovieMetadata_MovieMetadata_Id = table.Column<int>(nullable: true),
+ Barcode = table.Column<string>(maxLength: 255, nullable: true),
+ LabelNumber = table.Column<string>(maxLength: 255, nullable: true),
+ MusicAlbumMetadata_Country = table.Column<string>(maxLength: 2, nullable: true),
+ MusicAlbumMetadata_MusicAlbumMetadata_Id = table.Column<int>(nullable: true),
+ PhotoMetadata_PhotoMetadata_Id = table.Column<int>(nullable: true),
+ SeasonMetadata_Outline = table.Column<string>(maxLength: 1024, nullable: true),
+ SeasonMetadata_SeasonMetadata_Id = table.Column<int>(nullable: true),
+ SeriesMetadata_Outline = table.Column<string>(maxLength: 1024, nullable: true),
+ SeriesMetadata_Plot = table.Column<string>(maxLength: 65535, nullable: true),
+ SeriesMetadata_Tagline = table.Column<string>(maxLength: 1024, nullable: true),
+ SeriesMetadata_Country = table.Column<string>(maxLength: 2, nullable: true),
+ SeriesMetadata_SeriesMetadata_Id = table.Column<int>(nullable: true),
+ TrackMetadata_TrackMetadata_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Metadata", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_BookMetadata_BookMetadata_Id",
+ column: x => x.BookMetadata_BookMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_CustomItemMetadata_CustomItemMetadata_Id",
+ column: x => x.CustomItemMetadata_CustomItemMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_EpisodeMetadata_EpisodeMetadata_Id",
+ column: x => x.EpisodeMetadata_EpisodeMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_MovieMetadata_MovieMetadata_Id",
+ column: x => x.MovieMetadata_MovieMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_MusicAlbumMetadata_MusicAlbumMetadata_Id",
+ column: x => x.MusicAlbumMetadata_MusicAlbumMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_PhotoMetadata_PhotoMetadata_Id",
+ column: x => x.PhotoMetadata_PhotoMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_SeasonMetadata_SeasonMetadata_Id",
+ column: x => x.SeasonMetadata_SeasonMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_SeriesMetadata_SeriesMetadata_Id",
+ column: x => x.SeriesMetadata_SeriesMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Metadata_LibraryItem_TrackMetadata_TrackMetadata_Id",
+ column: x => x.TrackMetadata_TrackMetadata_Id,
+ principalSchema: "jellyfin",
+ principalTable: "LibraryItem",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Artwork",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Path = table.Column<string>(maxLength: 65535, nullable: false),
+ Kind = table.Column<int>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ PersonRole_PersonRoles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Artwork", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Artwork_Metadata_PersonRole_PersonRoles_Id",
+ column: x => x.PersonRole_PersonRoles_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Company",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ RowVersion = table.Column<uint>(nullable: false),
+ Company_Parent_Id = table.Column<int>(nullable: true),
+ Company_Labels_Id = table.Column<int>(nullable: true),
+ Company_Networks_Id = table.Column<int>(nullable: true),
+ Company_Publishers_Id = table.Column<int>(nullable: true),
+ Company_Studios_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Company", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Company_Metadata_Company_Labels_Id",
+ column: x => x.Company_Labels_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Company_Metadata_Company_Networks_Id",
+ column: x => x.Company_Networks_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Company_Company_Company_Parent_Id",
+ column: x => x.Company_Parent_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Company",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Company_Metadata_Company_Publishers_Id",
+ column: x => x.Company_Publishers_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Company_Metadata_Company_Studios_Id",
+ column: x => x.Company_Studios_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Genre",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 255, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ PersonRole_PersonRoles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Genre", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Genre_Metadata_PersonRole_PersonRoles_Id",
+ column: x => x.PersonRole_PersonRoles_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "MetadataProviderId",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ ProviderId = table.Column<string>(maxLength: 255, nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ MetadataProvider_Id = table.Column<int>(nullable: true),
+ MetadataProviderId_Sources_Id = table.Column<int>(nullable: true),
+ PersonRole_PersonRoles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_MetadataProviderId", x => x.Id);
+ table.ForeignKey(
+ name: "FK_MetadataProviderId_Person_MetadataProviderId_Sources_Id",
+ column: x => x.MetadataProviderId_Sources_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Person",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_MetadataProviderId_PersonRole_MetadataProviderId_Sources_Id",
+ column: x => x.MetadataProviderId_Sources_Id,
+ principalSchema: "jellyfin",
+ principalTable: "PersonRole",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_MetadataProviderId_MetadataProvider_MetadataProvider_Id",
+ column: x => x.MetadataProvider_Id,
+ principalSchema: "jellyfin",
+ principalTable: "MetadataProvider",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_MetadataProviderId_Metadata_PersonRole_PersonRoles_Id",
+ column: x => x.PersonRole_PersonRoles_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "RatingSource",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Name = table.Column<string>(maxLength: 1024, nullable: true),
+ MaximumValue = table.Column<double>(nullable: false),
+ MinimumValue = table.Column<double>(nullable: false),
+ RowVersion = table.Column<uint>(nullable: false),
+ MetadataProviderId_Source_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_RatingSource", x => x.Id);
+ table.ForeignKey(
+ name: "FK_RatingSource_MetadataProviderId_MetadataProviderId_Source_Id",
+ column: x => x.MetadataProviderId_Source_Id,
+ principalSchema: "jellyfin",
+ principalTable: "MetadataProviderId",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Rating",
+ schema: "jellyfin",
+ columns: table => new
+ {
+ Id = table.Column<int>(nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Value = table.Column<double>(nullable: false),
+ Votes = table.Column<int>(nullable: true),
+ RowVersion = table.Column<uint>(nullable: false),
+ RatingSource_RatingType_Id = table.Column<int>(nullable: true),
+ PersonRole_PersonRoles_Id = table.Column<int>(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Rating", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Rating_Metadata_PersonRole_PersonRoles_Id",
+ column: x => x.PersonRole_PersonRoles_Id,
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_Rating_RatingSource_RatingSource_RatingType_Id",
+ column: x => x.RatingSource_RatingType_Id,
+ principalSchema: "jellyfin",
+ principalTable: "RatingSource",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Artwork_Kind",
+ schema: "jellyfin",
+ table: "Artwork",
+ column: "Kind");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Artwork_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "Artwork",
+ column: "PersonRole_PersonRoles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Chapter_Chapter_Chapters_Id",
+ schema: "jellyfin",
+ table: "Chapter",
+ column: "Chapter_Chapters_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CollectionItem_CollectionItem_CollectionItem_Id",
+ schema: "jellyfin",
+ table: "CollectionItem",
+ column: "CollectionItem_CollectionItem_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CollectionItem_CollectionItem_Next_Id",
+ schema: "jellyfin",
+ table: "CollectionItem",
+ column: "CollectionItem_Next_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CollectionItem_CollectionItem_Previous_Id",
+ schema: "jellyfin",
+ table: "CollectionItem",
+ column: "CollectionItem_Previous_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_CollectionItem_LibraryItem_Id",
+ schema: "jellyfin",
+ table: "CollectionItem",
+ column: "LibraryItem_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Company_Company_Labels_Id",
+ schema: "jellyfin",
+ table: "Company",
+ column: "Company_Labels_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Company_Company_Networks_Id",
+ schema: "jellyfin",
+ table: "Company",
+ column: "Company_Networks_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Company_Company_Parent_Id",
+ schema: "jellyfin",
+ table: "Company",
+ column: "Company_Parent_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Company_Company_Publishers_Id",
+ schema: "jellyfin",
+ table: "Company",
+ column: "Company_Publishers_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Company_Company_Studios_Id",
+ schema: "jellyfin",
+ table: "Company",
+ column: "Company_Studios_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Genre_Name",
+ schema: "jellyfin",
+ table: "Genre",
+ column: "Name",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Genre_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "Genre",
+ column: "PersonRole_PersonRoles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Group_Group_Groups_Id",
+ schema: "jellyfin",
+ table: "Group",
+ column: "Group_Groups_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryItem_Episode_Episodes_Id",
+ schema: "jellyfin",
+ table: "LibraryItem",
+ column: "Episode_Episodes_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryItem_LibraryRoot_Id",
+ schema: "jellyfin",
+ table: "LibraryItem",
+ column: "LibraryRoot_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryItem_UrlId",
+ schema: "jellyfin",
+ table: "LibraryItem",
+ column: "UrlId",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryItem_Season_Seasons_Id",
+ schema: "jellyfin",
+ table: "LibraryItem",
+ column: "Season_Seasons_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryItem_Track_Tracks_Id",
+ schema: "jellyfin",
+ table: "LibraryItem",
+ column: "Track_Tracks_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_LibraryRoot_Library_Id",
+ schema: "jellyfin",
+ table: "LibraryRoot",
+ column: "Library_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MediaFile_MediaFile_MediaFiles_Id",
+ schema: "jellyfin",
+ table: "MediaFile",
+ column: "MediaFile_MediaFiles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MediaFileStream_MediaFileStream_MediaFileStreams_Id",
+ schema: "jellyfin",
+ table: "MediaFileStream",
+ column: "MediaFileStream_MediaFileStreams_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_BookMetadata_BookMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "BookMetadata_BookMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_CompanyMetadata_CompanyMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "CompanyMetadata_CompanyMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_CustomItemMetadata_CustomItemMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "CustomItemMetadata_CustomItemMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_EpisodeMetadata_EpisodeMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "EpisodeMetadata_EpisodeMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_MovieMetadata_MovieMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "MovieMetadata_MovieMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_MusicAlbumMetadata_MusicAlbumMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "MusicAlbumMetadata_MusicAlbumMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_PhotoMetadata_PhotoMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "PhotoMetadata_PhotoMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_SeasonMetadata_SeasonMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "SeasonMetadata_SeasonMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_SeriesMetadata_SeriesMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "SeriesMetadata_SeriesMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Metadata_TrackMetadata_TrackMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "TrackMetadata_TrackMetadata_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MetadataProviderId_MetadataProviderId_Sources_Id",
+ schema: "jellyfin",
+ table: "MetadataProviderId",
+ column: "MetadataProviderId_Sources_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MetadataProviderId_MetadataProvider_Id",
+ schema: "jellyfin",
+ table: "MetadataProviderId",
+ column: "MetadataProvider_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_MetadataProviderId_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "MetadataProviderId",
+ column: "PersonRole_PersonRoles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Permission_Permission_GroupPermissions_Id",
+ schema: "jellyfin",
+ table: "Permission",
+ column: "Permission_GroupPermissions_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Permission_Permission_Permissions_Id",
+ schema: "jellyfin",
+ table: "Permission",
+ column: "Permission_Permissions_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonRole_Artwork_Artwork_Id",
+ schema: "jellyfin",
+ table: "PersonRole",
+ column: "Artwork_Artwork_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonRole_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "PersonRole",
+ column: "PersonRole_PersonRoles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PersonRole_Person_Id",
+ schema: "jellyfin",
+ table: "PersonRole",
+ column: "Person_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Preference_Preference_Preferences_Id",
+ schema: "jellyfin",
+ table: "Preference",
+ column: "Preference_Preferences_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ProviderMapping_ProviderMapping_ProviderMappings_Id",
+ schema: "jellyfin",
+ table: "ProviderMapping",
+ column: "ProviderMapping_ProviderMappings_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Rating_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "Rating",
+ column: "PersonRole_PersonRoles_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Rating_RatingSource_RatingType_Id",
+ schema: "jellyfin",
+ table: "Rating",
+ column: "RatingSource_RatingType_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RatingSource_MetadataProviderId_Source_Id",
+ schema: "jellyfin",
+ table: "RatingSource",
+ column: "MetadataProviderId_Source_Id");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Release_Release_Releases_Id",
+ schema: "jellyfin",
+ table: "Release",
+ column: "Release_Releases_Id");
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_PersonRole_Metadata_PersonRole_PersonRoles_Id",
+ schema: "jellyfin",
+ table: "PersonRole",
+ column: "PersonRole_PersonRoles_Id",
+ principalSchema: "jellyfin",
+ principalTable: "Metadata",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_PersonRole_Artwork_Artwork_Artwork_Id",
+ schema: "jellyfin",
+ table: "PersonRole",
+ column: "Artwork_Artwork_Id",
+ principalSchema: "jellyfin",
+ principalTable: "Artwork",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Metadata_Company_CompanyMetadata_CompanyMetadata_Id",
+ schema: "jellyfin",
+ table: "Metadata",
+ column: "CompanyMetadata_CompanyMetadata_Id",
+ principalSchema: "jellyfin",
+ principalTable: "Company",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_Company_Metadata_Company_Labels_Id",
+ schema: "jellyfin",
+ table: "Company");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Company_Metadata_Company_Networks_Id",
+ schema: "jellyfin",
+ table: "Company");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Company_Metadata_Company_Publishers_Id",
+ schema: "jellyfin",
+ table: "Company");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Company_Metadata_Company_Studios_Id",
+ schema: "jellyfin",
+ table: "Company");
+
+ migrationBuilder.DropTable(
+ name: "ActivityLog",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Chapter",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "CollectionItem",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Genre",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "MediaFileStream",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Permission",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Preference",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "ProviderMapping",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Rating",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Collection",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "MediaFile",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Group",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "RatingSource",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Release",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "User",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "MetadataProviderId",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "PersonRole",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "MetadataProvider",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Artwork",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Person",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Metadata",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "LibraryItem",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Company",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "LibraryRoot",
+ schema: "jellyfin");
+
+ migrationBuilder.DropTable(
+ name: "Library",
+ schema: "jellyfin");
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs b/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs
new file mode 100644
index 000000000..72a4a8c3b
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/DesignTimeJellyfinDbFactory.cs
@@ -0,0 +1,20 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ /// <summary>
+ /// The design time factory for <see cref="JellyfinDb"/>.
+ /// This is only used for the creation of migrations and not during runtime.
+ /// </summary>
+ internal class DesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory<JellyfinDb>
+ {
+ public JellyfinDb CreateDbContext(string[] args)
+ {
+ var optionsBuilder = new DbContextOptionsBuilder<JellyfinDb>();
+ optionsBuilder.UseSqlite("Data Source=jellyfin.db");
+
+ return new JellyfinDb(optionsBuilder.Options);
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
new file mode 100644
index 000000000..8cdd101af
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
@@ -0,0 +1,1511 @@
+#pragma warning disable CS1591
+
+// <auto-generated />
+using System;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ [DbContext(typeof(JellyfinDb))]
+ partial class JellyfinDbModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("jellyfin")
+ .HasAnnotation("ProductVersion", "3.1.3");
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateCreated")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ItemId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<int>("LogSeverity")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Overview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ShortOverview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ActivityLog");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Artwork", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Kind");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("Artwork");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Chapter_Chapters_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(3);
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<long?>("TimeEnd")
+ .HasColumnType("INTEGER");
+
+ b.Property<long>("TimeStart")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Chapter_Chapters_Id");
+
+ b.ToTable("Chapter");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Collection", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Collection");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CollectionItem", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_CollectionItem_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_Next_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("CollectionItem_Previous_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("LibraryItem_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CollectionItem_CollectionItem_Id");
+
+ b.HasIndex("CollectionItem_Next_Id");
+
+ b.HasIndex("CollectionItem_Previous_Id");
+
+ b.HasIndex("LibraryItem_Id");
+
+ b.ToTable("CollectionItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Company", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Labels_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Networks_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Parent_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Publishers_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Company_Studios_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Company_Labels_Id");
+
+ b.HasIndex("Company_Networks_Id");
+
+ b.HasIndex("Company_Parent_Id");
+
+ b.HasIndex("Company_Publishers_Id");
+
+ b.HasIndex("Company_Studios_Id");
+
+ b.ToTable("Company");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Genre", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("Genre");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Group", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Group_Groups_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Group_Groups_Id");
+
+ b.ToTable("Group");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Library", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Library");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryItem", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("LibraryRoot_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("UrlId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("LibraryRoot_Id");
+
+ b.HasIndex("UrlId")
+ .IsUnique();
+
+ b.ToTable("LibraryItem");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("LibraryItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryRoot", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Library_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("NetworkPath")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Library_Id");
+
+ b.ToTable("LibraryRoot");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFile", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MediaFile_MediaFiles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MediaFile_MediaFiles_Id");
+
+ b.ToTable("MediaFile");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFileStream", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MediaFileStream_MediaFileStreams_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("StreamNumber")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MediaFileStream_MediaFileStreams_Id");
+
+ b.ToTable("MediaFileStream");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Metadata", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("DateModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Discriminator")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Language")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(3);
+
+ b.Property<string>("OriginalTitle")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<DateTimeOffset?>("ReleaseDate")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SortTitle")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Title")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasKey("Id");
+
+ b.ToTable("Metadata");
+
+ b.HasDiscriminator<string>("Discriminator").HasValue("Metadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProvider", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("MetadataProvider");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProviderId", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MetadataProviderId_Sources_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MetadataProvider_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MetadataProviderId_Sources_Id");
+
+ b.HasIndex("MetadataProvider_Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.ToTable("MetadataProviderId");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Permission_GroupPermissions_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Permission_Permissions_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("Value")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Permission_GroupPermissions_Id");
+
+ b.HasIndex("Permission_Permissions_Id");
+
+ b.ToTable("Permission");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Person", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime>("DateModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SourceId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<Guid>("UrlId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("Person");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PersonRole", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Artwork_Artwork_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Person_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Role")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Artwork_Artwork_Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.HasIndex("Person_Id");
+
+ b.ToTable("PersonRole");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Preference_Preferences_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Preference_Preferences_Id");
+
+ b.ToTable("Preference");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ProviderMapping", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderData")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("ProviderMapping_ProviderMappings_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ProviderName")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("ProviderSecrets")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderMapping_ProviderMappings_Id");
+
+ b.ToTable("ProviderMapping");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Rating", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("PersonRole_PersonRoles_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("RatingSource_RatingType_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("Value")
+ .HasColumnType("REAL");
+
+ b.Property<int?>("Votes")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PersonRole_PersonRoles_Id");
+
+ b.HasIndex("RatingSource_RatingType_Id");
+
+ b.ToTable("Rating");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.RatingSource", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("MaximumValue")
+ .HasColumnType("REAL");
+
+ b.Property<int?>("MetadataProviderId_Source_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("MinimumValue")
+ .HasColumnType("REAL");
+
+ b.Property<string>("Name")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MetadataProviderId_Source_Id");
+
+ b.ToTable("RatingSource");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Release", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<int?>("Release_Releases_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Release_Releases_Id");
+
+ b.ToTable("Release");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("AudioLanguagePreference")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("AuthenticationProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool?>("DisplayCollectionsView")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("DisplayMissingEpisodes")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("EnableNextEpisodeAutoPlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("EnableUserPreferenceAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("GroupedFolders")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool?>("HidePlayedInLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("InvalidLoginAttemptCount")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("LatestItemExcludes")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("LoginAttemptsBeforeLockout")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("MustUpdatePassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("MyMediaExcludes")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("OrderedViews")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Password")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool>("PlayDefaultAudioTrack")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("RememberAudioSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool?>("RememberSubtitleSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SubtitleLanguagePrefernce")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("SubtitleMode")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Username")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.HasKey("Id");
+
+ b.ToTable("User");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Book", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Book");
+
+ b.HasDiscriminator().HasValue("Book");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItem", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("LibraryItem");
+
+ b.HasDiscriminator().HasValue("CustomItem");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Episode", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("EpisodeNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Episode_Episodes_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Episode_Episodes_Id");
+
+ b.ToTable("Episode");
+
+ b.HasDiscriminator().HasValue("Episode");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Movie", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Movie");
+
+ b.HasDiscriminator().HasValue("Movie");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbum", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("MusicAlbum");
+
+ b.HasDiscriminator().HasValue("MusicAlbum");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Photo", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.ToTable("Photo");
+
+ b.HasDiscriminator().HasValue("Photo");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Season", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("SeasonNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Season_Seasons_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Season_Seasons_Id");
+
+ b.ToTable("Season");
+
+ b.HasDiscriminator().HasValue("Season");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Series", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("AirsDayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTimeOffset?>("AirsTime")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTimeOffset?>("FirstAired")
+ .HasColumnType("TEXT");
+
+ b.ToTable("Series");
+
+ b.HasDiscriminator().HasValue("Series");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Track", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.LibraryItem");
+
+ b.Property<int?>("TrackNumber")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("Track_Tracks_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("Track_Tracks_Id");
+
+ b.ToTable("Track");
+
+ b.HasDiscriminator().HasValue("Track");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.BookMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("BookMetadata_BookMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<long?>("ISBN")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("BookMetadata_BookMetadata_Id");
+
+ b.ToTable("Metadata");
+
+ b.HasDiscriminator().HasValue("BookMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CompanyMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("CompanyMetadata_CompanyMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("Description")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Headquarters")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Homepage")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("CompanyMetadata_CompanyMetadata_Id");
+
+ b.ToTable("CompanyMetadata");
+
+ b.HasDiscriminator().HasValue("CompanyMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("CustomItemMetadata_CustomItemMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("CustomItemMetadata_CustomItemMetadata_Id");
+
+ b.ToTable("CustomItemMetadata");
+
+ b.HasDiscriminator().HasValue("CustomItemMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.EpisodeMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("EpisodeMetadata_EpisodeMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("EpisodeMetadata_EpisodeMetadata_Id");
+
+ b.ToTable("EpisodeMetadata");
+
+ b.HasDiscriminator().HasValue("EpisodeMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MovieMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Country")
+ .HasColumnName("MovieMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<int?>("MovieMetadata_MovieMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Outline")
+ .HasColumnName("MovieMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnName("MovieMetadata_Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("Tagline")
+ .HasColumnName("MovieMetadata_Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("MovieMetadata_MovieMetadata_Id");
+
+ b.ToTable("MovieMetadata");
+
+ b.HasDiscriminator().HasValue("MovieMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbumMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Barcode")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("Country")
+ .HasColumnName("MusicAlbumMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("LabelNumber")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int?>("MusicAlbumMetadata_MusicAlbumMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("MusicAlbumMetadata_MusicAlbumMetadata_Id");
+
+ b.ToTable("MusicAlbumMetadata");
+
+ b.HasDiscriminator().HasValue("MusicAlbumMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PhotoMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("PhotoMetadata_PhotoMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("PhotoMetadata_PhotoMetadata_Id");
+
+ b.ToTable("PhotoMetadata");
+
+ b.HasDiscriminator().HasValue("PhotoMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeasonMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Outline")
+ .HasColumnName("SeasonMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<int?>("SeasonMetadata_SeasonMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("SeasonMetadata_SeasonMetadata_Id");
+
+ b.ToTable("SeasonMetadata");
+
+ b.HasDiscriminator().HasValue("SeasonMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeriesMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<string>("Country")
+ .HasColumnName("SeriesMetadata_Country")
+ .HasColumnType("TEXT")
+ .HasMaxLength(2);
+
+ b.Property<string>("Outline")
+ .HasColumnName("SeriesMetadata_Outline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.Property<string>("Plot")
+ .HasColumnName("SeriesMetadata_Plot")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<int?>("SeriesMetadata_SeriesMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Tagline")
+ .HasColumnName("SeriesMetadata_Tagline")
+ .HasColumnType("TEXT")
+ .HasMaxLength(1024);
+
+ b.HasIndex("SeriesMetadata_SeriesMetadata_Id");
+
+ b.ToTable("SeriesMetadata");
+
+ b.HasDiscriminator().HasValue("SeriesMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.TrackMetadata", b =>
+ {
+ b.HasBaseType("Jellyfin.Data.Entities.Metadata");
+
+ b.Property<int?>("TrackMetadata_TrackMetadata_Id")
+ .HasColumnType("INTEGER");
+
+ b.HasIndex("TrackMetadata_TrackMetadata_Id");
+
+ b.ToTable("TrackMetadata");
+
+ b.HasDiscriminator().HasValue("TrackMetadata");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Artwork", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Artwork")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Chapter", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Release", null)
+ .WithMany("Chapters")
+ .HasForeignKey("Chapter_Chapters_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CollectionItem", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Collection", null)
+ .WithMany("CollectionItem")
+ .HasForeignKey("CollectionItem_CollectionItem_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CollectionItem", "Next")
+ .WithMany()
+ .HasForeignKey("CollectionItem_Next_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CollectionItem", "Previous")
+ .WithMany()
+ .HasForeignKey("CollectionItem_Previous_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.LibraryItem", "LibraryItem")
+ .WithMany()
+ .HasForeignKey("LibraryItem_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Company", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbumMetadata", null)
+ .WithMany("Labels")
+ .HasForeignKey("Company_Labels_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.SeriesMetadata", null)
+ .WithMany("Networks")
+ .HasForeignKey("Company_Networks_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Company", "Parent")
+ .WithMany()
+ .HasForeignKey("Company_Parent_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.BookMetadata", null)
+ .WithMany("Publishers")
+ .HasForeignKey("Company_Publishers_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.MovieMetadata", null)
+ .WithMany("Studios")
+ .HasForeignKey("Company_Studios_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Genre", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Genres")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Group", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Groups")
+ .HasForeignKey("Group_Groups_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryItem", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.LibraryRoot", "LibraryRoot")
+ .WithMany()
+ .HasForeignKey("LibraryRoot_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.LibraryRoot", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Library", "Library")
+ .WithMany()
+ .HasForeignKey("Library_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFile", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Release", null)
+ .WithMany("MediaFiles")
+ .HasForeignKey("MediaFile_MediaFiles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MediaFileStream", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MediaFile", null)
+ .WithMany("MediaFileStreams")
+ .HasForeignKey("MediaFileStream_MediaFileStreams_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MetadataProviderId", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Person", null)
+ .WithMany("Sources")
+ .HasForeignKey("MetadataProviderId_Sources_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.PersonRole", null)
+ .WithMany("Sources")
+ .HasForeignKey("MetadataProviderId_Sources_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.MetadataProvider", "MetadataProvider")
+ .WithMany()
+ .HasForeignKey("MetadataProvider_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Sources")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("GroupPermissions")
+ .HasForeignKey("Permission_GroupPermissions_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Permissions")
+ .HasForeignKey("Permission_Permissions_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PersonRole", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Artwork", "Artwork")
+ .WithMany()
+ .HasForeignKey("Artwork_Artwork_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("PersonRoles")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.Person", "Person")
+ .WithMany()
+ .HasForeignKey("Person_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ProviderMapping", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Group", null)
+ .WithMany("ProviderMappings")
+ .HasForeignKey("ProviderMapping_ProviderMappings_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("ProviderMappings")
+ .HasForeignKey("ProviderMapping_ProviderMappings_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Rating", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Metadata", null)
+ .WithMany("Ratings")
+ .HasForeignKey("PersonRole_PersonRoles_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.RatingSource", "RatingType")
+ .WithMany()
+ .HasForeignKey("RatingSource_RatingType_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.RatingSource", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MetadataProviderId", "Source")
+ .WithMany()
+ .HasForeignKey("MetadataProviderId_Source_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Release", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Book", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id");
+
+ b.HasOne("Jellyfin.Data.Entities.CustomItem", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id1");
+
+ b.HasOne("Jellyfin.Data.Entities.Episode", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id2");
+
+ b.HasOne("Jellyfin.Data.Entities.Movie", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id3");
+
+ b.HasOne("Jellyfin.Data.Entities.Photo", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id4");
+
+ b.HasOne("Jellyfin.Data.Entities.Track", null)
+ .WithMany("Releases")
+ .HasForeignKey("Release_Releases_Id")
+ .HasConstraintName("FK_Release_LibraryItem_Release_Releases_Id5");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Episode", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Season", null)
+ .WithMany("Episodes")
+ .HasForeignKey("Episode_Episodes_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Season", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Series", null)
+ .WithMany("Seasons")
+ .HasForeignKey("Season_Seasons_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Track", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbum", null)
+ .WithMany("Tracks")
+ .HasForeignKey("Track_Tracks_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.BookMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Book", null)
+ .WithMany("BookMetadata")
+ .HasForeignKey("BookMetadata_BookMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CompanyMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Company", null)
+ .WithMany("CompanyMetadata")
+ .HasForeignKey("CompanyMetadata_CompanyMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.CustomItem", null)
+ .WithMany("CustomItemMetadata")
+ .HasForeignKey("CustomItemMetadata_CustomItemMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.EpisodeMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Episode", null)
+ .WithMany("EpisodeMetadata")
+ .HasForeignKey("EpisodeMetadata_EpisodeMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MovieMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Movie", null)
+ .WithMany("MovieMetadata")
+ .HasForeignKey("MovieMetadata_MovieMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.MusicAlbumMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.MusicAlbum", null)
+ .WithMany("MusicAlbumMetadata")
+ .HasForeignKey("MusicAlbumMetadata_MusicAlbumMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.PhotoMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Photo", null)
+ .WithMany("PhotoMetadata")
+ .HasForeignKey("PhotoMetadata_PhotoMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeasonMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Season", null)
+ .WithMany("SeasonMetadata")
+ .HasForeignKey("SeasonMetadata_SeasonMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.SeriesMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Series", null)
+ .WithMany("SeriesMetadata")
+ .HasForeignKey("SeriesMetadata_SeriesMetadata_Id");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.TrackMetadata", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.Track", null)
+ .WithMany("TrackMetadata")
+ .HasForeignKey("TrackMetadata_TrackMetadata_Id");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 88114d999..4194070aa 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -13,6 +13,9 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
+
+ <!-- Used for generating migrations for EF Core -->
+ <GenerateRuntimeConfigurationFiles>True</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
<ItemGroup>
@@ -41,6 +44,10 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.7.82" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.3" />
<PackageReference Include="prometheus-net" Version="3.5.0" />
diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs
index b5ea04dca..82e304586 100644
--- a/Jellyfin.Server/Migrations/MigrationRunner.cs
+++ b/Jellyfin.Server/Migrations/MigrationRunner.cs
@@ -16,7 +16,8 @@ namespace Jellyfin.Server.Migrations
internal static readonly IMigrationRoutine[] Migrations =
{
new Routines.DisableTranscodingThrottling(),
- new Routines.CreateUserLoggingConfigFile()
+ new Routines.CreateUserLoggingConfigFile(),
+ new Routines.MigrateActivityLogDb()
};
/// <summary>
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
new file mode 100644
index 000000000..9f1f5b92e
--- /dev/null
+++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
@@ -0,0 +1,109 @@
+#pragma warning disable CS1591
+
+using System;
+using System.IO;
+using Emby.Server.Implementations.Data;
+using Jellyfin.Data.Entities;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using SQLitePCL.pretty;
+
+namespace Jellyfin.Server.Migrations.Routines
+{
+ public class MigrateActivityLogDb : IMigrationRoutine
+ {
+ private const string DbFilename = "activitylog.db";
+
+ public Guid Id => Guid.Parse("3793eb59-bc8c-456c-8b9f-bd5a62a42978");
+
+ public string Name => "MigrateActivityLogDatabase";
+
+ public void Perform(CoreAppHost host, ILogger logger)
+ {
+ var dataPath = host.ServerConfigurationManager.ApplicationPaths.DataPath;
+ using (var connection = SQLite3.Open(
+ Path.Combine(dataPath, DbFilename),
+ ConnectionFlags.ReadOnly,
+ null))
+ {
+ logger.LogInformation("Migrating the database may take a while, do not stop Jellyfin.");
+ using var dbContext = host.ServiceProvider.GetService<JellyfinDb>();
+
+ var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id ASC");
+
+ // Make sure that the database is empty in case of failed migration due to power outages, etc.
+ dbContext.ActivityLogs.RemoveRange(dbContext.ActivityLogs);
+ dbContext.SaveChanges();
+ // Reset the autoincrement counter
+ dbContext.Database.ExecuteSqlRaw("UPDATE sqlite_sequence SET seq = 0 WHERE name = 'ActivityLog';");
+ dbContext.SaveChanges();
+
+ foreach (var entry in queryResult)
+ {
+ var newEntry = new ActivityLog(
+ entry[1].ToString(),
+ entry[4].ToString(),
+ entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString()),
+ entry[7].ReadDateTime(),
+ ParseLogLevel(entry[8].ToString()));
+
+ if (entry[2].SQLiteType != SQLiteType.Null)
+ {
+ newEntry.Overview = entry[2].ToString();
+ }
+
+ if (entry[3].SQLiteType != SQLiteType.Null)
+ {
+ newEntry.ShortOverview = entry[3].ToString();
+ }
+
+ if (entry[5].SQLiteType != SQLiteType.Null)
+ {
+ newEntry.ItemId = entry[5].ToString();
+ }
+
+ dbContext.ActivityLogs.Add(newEntry);
+ dbContext.SaveChanges();
+ }
+ }
+
+ try
+ {
+ File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
+ }
+ catch (IOException e)
+ {
+ logger.LogError(e, "Error renaming legacy activity log database to 'activitylog.db.old'");
+ }
+ }
+
+ private LogLevel ParseLogLevel(string entry)
+ {
+ if (string.Equals(entry, "Debug", StringComparison.OrdinalIgnoreCase))
+ {
+ return LogLevel.Debug;
+ }
+
+ if (string.Equals(entry, "Information", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(entry, "Info", StringComparison.OrdinalIgnoreCase))
+ {
+ return LogLevel.Information;
+ }
+
+ if (string.Equals(entry, "Warning", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(entry, "Warn", StringComparison.OrdinalIgnoreCase))
+ {
+ return LogLevel.Warning;
+ }
+
+ if (string.Equals(entry, "Error", StringComparison.OrdinalIgnoreCase))
+ {
+ return LogLevel.Error;
+ }
+
+ return LogLevel.Trace;
+ }
+ }
+}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index a54640b2f..997b1c45a 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -759,13 +759,14 @@ namespace MediaBrowser.Api.Library
{
try
{
- _activityManager.Create(new ActivityLogEntry
+ _activityManager.Create(new Jellyfin.Data.Entities.ActivityLog(
+ string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
+ "UserDownloadingContent",
+ auth.UserId,
+ DateTime.UtcNow,
+ LogLevel.Trace)
{
- Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
- Type = "UserDownloadingContent",
ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device),
- UserId = auth.UserId
-
});
}
catch
diff --git a/MediaBrowser.Api/System/ActivityLogService.cs b/MediaBrowser.Api/System/ActivityLogService.cs
index f95fa7ca0..0a5fc9433 100644
--- a/MediaBrowser.Api/System/ActivityLogService.cs
+++ b/MediaBrowser.Api/System/ActivityLogService.cs
@@ -53,7 +53,7 @@ namespace MediaBrowser.Api.System
(DateTime?)null :
DateTime.Parse(request.MinDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
- var result = _activityManager.GetActivityLogEntries(minDate, request.HasUserId, request.StartIndex, request.Limit);
+ var result = _activityManager.GetPagedResult(request.StartIndex, request.Limit);
return ToOptimizedResult(result);
}
diff --git a/MediaBrowser.Model/Activity/ActivityLogEntry.cs b/MediaBrowser.Model/Activity/ActivityLogEntry.cs
index 80f01b66e..5ab904394 100644
--- a/MediaBrowser.Model/Activity/ActivityLogEntry.cs
+++ b/MediaBrowser.Model/Activity/ActivityLogEntry.cs
@@ -59,6 +59,7 @@ namespace MediaBrowser.Model.Activity
/// Gets or sets the user primary image tag.
/// </summary>
/// <value>The user primary image tag.</value>
+ [Obsolete("UserPrimaryImageTag is not used.")]
public string UserPrimaryImageTag { get; set; }
/// <summary>
diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs
index f336f5272..6742dc8fc 100644
--- a/MediaBrowser.Model/Activity/IActivityManager.cs
+++ b/MediaBrowser.Model/Activity/IActivityManager.cs
@@ -1,6 +1,10 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Querying;
@@ -10,10 +14,15 @@ namespace MediaBrowser.Model.Activity
{
event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
- void Create(ActivityLogEntry entry);
+ void Create(ActivityLog entry);
- QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit);
+ Task CreateAsync(ActivityLog entry);
- QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? x, int? y);
+ QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit);
+
+ QueryResult<ActivityLogEntry> GetPagedResult(
+ Func<IQueryable<ActivityLog>, IEnumerable<ActivityLog>> func,
+ int? startIndex,
+ int? limit);
}
}
diff --git a/MediaBrowser.Model/Activity/IActivityRepository.cs b/MediaBrowser.Model/Activity/IActivityRepository.cs
deleted file mode 100644
index 66144ec47..000000000
--- a/MediaBrowser.Model/Activity/IActivityRepository.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using MediaBrowser.Model.Querying;
-
-namespace MediaBrowser.Model.Activity
-{
- public interface IActivityRepository
- {
- void Create(ActivityLogEntry entry);
-
- QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? z, int? startIndex, int? limit);
- }
-}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index b41d0af1d..5c6e313e0 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -37,6 +37,9 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Jellyfin.Data\Jellyfin.Data.csproj" />
+ </ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
diff --git a/MediaBrowser.sln b/MediaBrowser.sln
index a1dbe8047..6d01b0dcd 100644
--- a/MediaBrowser.sln
+++ b/MediaBrowser.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26730.3
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}"
EndProject
@@ -46,23 +46,25 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Drawing.Skia", "Jellyfin.Drawing.Skia\Jellyfin.Drawing.Skia.csproj", "{154872D9-6C12-4007-96E3-8F70A58386CE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Api", "Jellyfin.Api\Jellyfin.Api.csproj", "{DFBEFB4C-DA19-4143-98B7-27320C7F7163}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Api", "Jellyfin.Api\Jellyfin.Api.csproj", "{DFBEFB4C-DA19-4143-98B7-27320C7F7163}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Common.Tests", "tests\Jellyfin.Common.Tests\Jellyfin.Common.Tests.csproj", "{DF194677-DFD3-42AF-9F75-D44D5A416478}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Common.Tests", "tests\Jellyfin.Common.Tests\Jellyfin.Common.Tests.csproj", "{DF194677-DFD3-42AF-9F75-D44D5A416478}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.MediaEncoding.Tests", "tests\Jellyfin.MediaEncoding.Tests\Jellyfin.MediaEncoding.Tests.csproj", "{28464062-0939-4AA7-9F7B-24DDDA61A7C0}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Naming.Tests", "tests\Jellyfin.Naming.Tests\Jellyfin.Naming.Tests.csproj", "{3998657B-1CCC-49DD-A19F-275DC8495F57}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Naming.Tests", "tests\Jellyfin.Naming.Tests\Jellyfin.Naming.Tests.csproj", "{3998657B-1CCC-49DD-A19F-275DC8495F57}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Api.Tests", "tests\Jellyfin.Api.Tests\Jellyfin.Api.Tests.csproj", "{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Api.Tests", "tests\Jellyfin.Api.Tests\Jellyfin.Api.Tests.csproj", "{A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Implementations.Tests", "tests\Jellyfin.Server.Implementations.Tests\Jellyfin.Server.Implementations.Tests.csproj", "{2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server.Implementations.Tests", "tests\Jellyfin.Server.Implementations.Tests\Jellyfin.Server.Implementations.Tests.csproj", "{2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Controller.Tests", "tests\Jellyfin.Controller.Tests\Jellyfin.Controller.Tests.csproj", "{462584F7-5023-4019-9EAC-B98CA458C0A0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Controller.Tests", "tests\Jellyfin.Controller.Tests\Jellyfin.Controller.Tests.csproj", "{462584F7-5023-4019-9EAC-B98CA458C0A0}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Data", "Jellyfin.Data\Jellyfin.Data.csproj", "{F03299F2-469F-40EF-A655-3766F97A5702}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Data", "Jellyfin.Data\Jellyfin.Data.csproj", "{F03299F2-469F-40EF-A655-3766F97A5702}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server.Implementations", "Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj", "{DAE48069-6D86-4BA6-B148-D1D49B6DDA52}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -114,10 +116,6 @@ Global
{713F42B5-878E-499D-A878-E4C652B1D5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{713F42B5-878E-499D-A878-E4C652B1D5E8}.Release|Any CPU.Build.0 = Release|Any CPU
- {88AE38DF-19D7-406F-A6A9-09527719A21E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {88AE38DF-19D7-406F-A6A9-09527719A21E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {88AE38DF-19D7-406F-A6A9-09527719A21E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {88AE38DF-19D7-406F-A6A9-09527719A21E}.Release|Any CPU.Build.0 = Release|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -182,10 +180,22 @@ Global
{F03299F2-469F-40EF-A655-3766F97A5702}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F03299F2-469F-40EF-A655-3766F97A5702}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F03299F2-469F-40EF-A655-3766F97A5702}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DAE48069-6D86-4BA6-B148-D1D49B6DDA52}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {3998657B-1CCC-49DD-A19F-275DC8495F57} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {462584F7-5023-4019-9EAC-B98CA458C0A0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
EndGlobalSection
@@ -207,12 +217,4 @@ Global
$0.DotNetNamingPolicy = $2
$2.DirectoryNamespaceAssociation = PrefixedHierarchical
EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {DF194677-DFD3-42AF-9F75-D44D5A416478} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {28464062-0939-4AA7-9F7B-24DDDA61A7C0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {3998657B-1CCC-49DD-A19F-275DC8495F57} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {A2FD0A10-8F62-4F9D-B171-FFDF9F0AFA9D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {2E3A1B4B-4225-4AAA-8B29-0181A84E7AEE} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- {462584F7-5023-4019-9EAC-B98CA458C0A0} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
- EndGlobalSection
EndGlobal