mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-01-27 13:38:20 +00:00
Merge remote-tracking branch 'upstream/master' into 3.1.7
This commit is contained in:
@@ -1,590 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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.Library;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Notifications;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Updates;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.Activity
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point for the activity logger.
|
||||
/// </summary>
|
||||
public sealed class ActivityLogEntryPoint : IServerEntryPoint
|
||||
{
|
||||
private readonly ILogger<ActivityLogEntryPoint> _logger;
|
||||
private readonly IInstallationManager _installationManager;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly ITaskManager _taskManager;
|
||||
private readonly IActivityManager _activityManager;
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly ISubtitleManager _subManager;
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityLogEntryPoint"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
/// <param name="taskManager">The task manager.</param>
|
||||
/// <param name="activityManager">The activity manager.</param>
|
||||
/// <param name="localization">The localization manager.</param>
|
||||
/// <param name="installationManager">The installation manager.</param>
|
||||
/// <param name="subManager">The subtitle manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
public ActivityLogEntryPoint(
|
||||
ILogger<ActivityLogEntryPoint> logger,
|
||||
ISessionManager sessionManager,
|
||||
ITaskManager taskManager,
|
||||
IActivityManager activityManager,
|
||||
ILocalizationManager localization,
|
||||
IInstallationManager installationManager,
|
||||
ISubtitleManager subManager,
|
||||
IUserManager userManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_sessionManager = sessionManager;
|
||||
_taskManager = taskManager;
|
||||
_activityManager = activityManager;
|
||||
_localization = localization;
|
||||
_installationManager = installationManager;
|
||||
_subManager = subManager;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RunAsync()
|
||||
{
|
||||
_taskManager.TaskCompleted += OnTaskCompleted;
|
||||
|
||||
_installationManager.PluginInstalled += OnPluginInstalled;
|
||||
_installationManager.PluginUninstalled += OnPluginUninstalled;
|
||||
_installationManager.PluginUpdated += OnPluginUpdated;
|
||||
_installationManager.PackageInstallationFailed += OnPackageInstallationFailed;
|
||||
|
||||
_sessionManager.SessionStarted += OnSessionStarted;
|
||||
_sessionManager.AuthenticationFailed += OnAuthenticationFailed;
|
||||
_sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded;
|
||||
_sessionManager.SessionEnded += OnSessionEnded;
|
||||
_sessionManager.PlaybackStart += OnPlaybackStart;
|
||||
_sessionManager.PlaybackStopped += OnPlaybackStopped;
|
||||
|
||||
_subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure;
|
||||
|
||||
_userManager.OnUserCreated += OnUserCreated;
|
||||
_userManager.OnUserPasswordChanged += OnUserPasswordChanged;
|
||||
_userManager.OnUserDeleted += OnUserDeleted;
|
||||
_userManager.OnUserLockedOut += OnUserLockedOut;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnUserLockedOut(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserLockedOutWithName"),
|
||||
e.Argument.Username),
|
||||
NotificationType.UserLockedOut.ToString(),
|
||||
e.Argument.Id)
|
||||
{
|
||||
LogSeverity = LogLevel.Error
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
|
||||
e.Provider,
|
||||
Notifications.NotificationEntryPoint.GetItemName(e.Item)),
|
||||
"SubtitleDownloadFailure",
|
||||
Guid.Empty)
|
||||
{
|
||||
ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||
ShortOverview = e.Exception.Message
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPlaybackStopped(object sender, PlaybackStopEventArgs e)
|
||||
{
|
||||
var item = e.MediaInfo;
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
_logger.LogWarning("PlaybackStopped reported with null media info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Item != null && e.Item.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var user = e.Users[0];
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"),
|
||||
user.Username,
|
||||
GetItemName(item),
|
||||
e.DeviceName),
|
||||
GetPlaybackStoppedNotificationType(item.MediaType),
|
||||
user.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPlaybackStart(object sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
var item = e.MediaInfo;
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
_logger.LogWarning("PlaybackStart reported with null media info.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Item != null && e.Item.IsThemeMedia)
|
||||
{
|
||||
// Don't report theme song or local trailer playback
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Users.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var user = e.Users.First();
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserStartedPlayingItemWithValues"),
|
||||
user.Username,
|
||||
GetItemName(item),
|
||||
e.DeviceName),
|
||||
GetPlaybackNotificationType(item.MediaType),
|
||||
user.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetItemName(BaseItemDto item)
|
||||
{
|
||||
var name = item.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(item.SeriesName))
|
||||
{
|
||||
name = item.SeriesName + " - " + name;
|
||||
}
|
||||
|
||||
if (item.Artists != null && item.Artists.Count > 0)
|
||||
{
|
||||
name = item.Artists[0] + " - " + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static string GetPlaybackNotificationType(string mediaType)
|
||||
{
|
||||
if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.AudioPlayback.ToString();
|
||||
}
|
||||
|
||||
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.VideoPlayback.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetPlaybackStoppedNotificationType(string mediaType)
|
||||
{
|
||||
if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.AudioPlaybackStopped.ToString();
|
||||
}
|
||||
|
||||
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return NotificationType.VideoPlaybackStopped.ToString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async void OnSessionEnded(object sender, SessionEventArgs e)
|
||||
{
|
||||
var session = e.SessionInfo;
|
||||
|
||||
if (string.IsNullOrEmpty(session.UserName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserOfflineFromDevice"),
|
||||
session.UserName,
|
||||
session.DeviceName),
|
||||
"SessionEnded",
|
||||
session.UserId)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("LabelIpAddressValue"),
|
||||
session.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnAuthenticationSucceeded(object sender, GenericEventArgs<AuthenticationResult> e)
|
||||
{
|
||||
var user = e.Argument.User;
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("AuthenticationSucceededWithUserName"),
|
||||
user.Name),
|
||||
"AuthenticationSucceeded",
|
||||
user.Id)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("LabelIpAddressValue"),
|
||||
e.Argument.SessionInfo.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnAuthenticationFailed(object sender, GenericEventArgs<AuthenticationRequest> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("FailedLoginAttemptWithUserName"),
|
||||
e.Argument.Username),
|
||||
"AuthenticationFailed",
|
||||
Guid.Empty)
|
||||
{
|
||||
LogSeverity = LogLevel.Error,
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("LabelIpAddressValue"),
|
||||
e.Argument.RemoteEndPoint),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserDeleted(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserDeletedWithName"),
|
||||
e.Argument.Username),
|
||||
"UserDeleted",
|
||||
Guid.Empty))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserPasswordChanged(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserPasswordChangedWithName"),
|
||||
e.Argument.Username),
|
||||
"UserPasswordChanged",
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnUserCreated(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserCreatedWithName"),
|
||||
e.Argument.Username),
|
||||
"UserCreated",
|
||||
e.Argument.Id))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionStarted(object sender, SessionEventArgs e)
|
||||
{
|
||||
var session = e.SessionInfo;
|
||||
|
||||
if (string.IsNullOrEmpty(session.UserName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("UserOnlineFromDevice"),
|
||||
session.UserName,
|
||||
session.DeviceName),
|
||||
"SessionStarted",
|
||||
session.UserId)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("LabelIpAddressValue"),
|
||||
session.RemoteEndPoint)
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPluginUpdated(object sender, InstallationInfo e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("PluginUpdatedWithName"),
|
||||
e.Name),
|
||||
NotificationType.PluginUpdateInstalled.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("VersionNumber"),
|
||||
e.Version),
|
||||
Overview = e.Changelog
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPluginUninstalled(object sender, IPlugin e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("PluginUninstalledWithName"),
|
||||
e.Name),
|
||||
NotificationType.PluginUninstalled.ToString(),
|
||||
Guid.Empty))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPluginInstalled(object sender, InstallationInfo e)
|
||||
{
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("PluginInstalledWithName"),
|
||||
e.Name),
|
||||
NotificationType.PluginInstalled.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("VersionNumber"),
|
||||
e.Version)
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e)
|
||||
{
|
||||
var installationInfo = e.InstallationInfo;
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("NameInstallFailed"),
|
||||
installationInfo.Name),
|
||||
NotificationType.InstallationFailed.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
ShortOverview = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("VersionNumber"),
|
||||
installationInfo.Version),
|
||||
Overview = e.Exception.Message
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
|
||||
{
|
||||
var result = e.Result;
|
||||
var task = e.Task;
|
||||
|
||||
if (task.ScheduledTask is IConfigurableScheduledTask activityTask
|
||||
&& !activityTask.IsLogged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var time = result.EndTimeUtc - result.StartTimeUtc;
|
||||
var runningTime = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
_localization.GetLocalizedString("LabelRunningTimeValue"),
|
||||
ToUserFriendlyString(time));
|
||||
|
||||
if (result.Status == TaskCompletionStatus.Failed)
|
||||
{
|
||||
var vals = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(e.Result.ErrorMessage))
|
||||
{
|
||||
vals.Add(e.Result.ErrorMessage);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(e.Result.LongErrorMessage))
|
||||
{
|
||||
vals.Add(e.Result.LongErrorMessage);
|
||||
}
|
||||
|
||||
await CreateLogEntry(new ActivityLog(
|
||||
string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
||||
NotificationType.TaskFailed.ToString(),
|
||||
Guid.Empty)
|
||||
{
|
||||
LogSeverity = LogLevel.Error,
|
||||
Overview = string.Join(Environment.NewLine, vals),
|
||||
ShortOverview = runningTime
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateLogEntry(ActivityLog entry)
|
||||
=> await _activityManager.CreateAsync(entry).ConfigureAwait(false);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_taskManager.TaskCompleted -= OnTaskCompleted;
|
||||
|
||||
_installationManager.PluginInstalled -= OnPluginInstalled;
|
||||
_installationManager.PluginUninstalled -= OnPluginUninstalled;
|
||||
_installationManager.PluginUpdated -= OnPluginUpdated;
|
||||
_installationManager.PackageInstallationFailed -= OnPackageInstallationFailed;
|
||||
|
||||
_sessionManager.SessionStarted -= OnSessionStarted;
|
||||
_sessionManager.AuthenticationFailed -= OnAuthenticationFailed;
|
||||
_sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded;
|
||||
_sessionManager.SessionEnded -= OnSessionEnded;
|
||||
|
||||
_sessionManager.PlaybackStart -= OnPlaybackStart;
|
||||
_sessionManager.PlaybackStopped -= OnPlaybackStopped;
|
||||
|
||||
_subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure;
|
||||
|
||||
_userManager.OnUserCreated -= OnUserCreated;
|
||||
_userManager.OnUserPasswordChanged -= OnUserPasswordChanged;
|
||||
_userManager.OnUserDeleted -= OnUserDeleted;
|
||||
_userManager.OnUserLockedOut -= OnUserLockedOut;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a user-friendly string for this TimeSpan instance.
|
||||
/// </summary>
|
||||
private static string ToUserFriendlyString(TimeSpan span)
|
||||
{
|
||||
const int DaysInYear = 365;
|
||||
const int DaysInMonth = 30;
|
||||
|
||||
// Get each non-zero value from TimeSpan component
|
||||
var values = new List<string>();
|
||||
|
||||
// Number of years
|
||||
int days = span.Days;
|
||||
if (days >= DaysInYear)
|
||||
{
|
||||
int years = days / DaysInYear;
|
||||
values.Add(CreateValueString(years, "year"));
|
||||
days %= DaysInYear;
|
||||
}
|
||||
|
||||
// Number of months
|
||||
if (days >= DaysInMonth)
|
||||
{
|
||||
int months = days / DaysInMonth;
|
||||
values.Add(CreateValueString(months, "month"));
|
||||
days = days % DaysInMonth;
|
||||
}
|
||||
|
||||
// Number of days
|
||||
if (days >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(days, "day"));
|
||||
}
|
||||
|
||||
// Number of hours
|
||||
if (span.Hours >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(span.Hours, "hour"));
|
||||
}
|
||||
|
||||
// Number of minutes
|
||||
if (span.Minutes >= 1)
|
||||
{
|
||||
values.Add(CreateValueString(span.Minutes, "minute"));
|
||||
}
|
||||
|
||||
// Number of seconds (include when 0 if no other components included)
|
||||
if (span.Seconds >= 1 || values.Count == 0)
|
||||
{
|
||||
values.Add(CreateValueString(span.Seconds, "second"));
|
||||
}
|
||||
|
||||
// Combine values into string
|
||||
var builder = new StringBuilder();
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
{
|
||||
if (builder.Length > 0)
|
||||
{
|
||||
builder.Append(i == values.Count - 1 ? " and " : ", ");
|
||||
}
|
||||
|
||||
builder.Append(values[i]);
|
||||
}
|
||||
|
||||
// Return result
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a string description of a time-span value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of this item.</param>
|
||||
/// <param name="description">The name of this item (singular form).</param>
|
||||
private static string CreateValueString(int value, string description)
|
||||
{
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0:#,##0} {1}",
|
||||
value,
|
||||
value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,6 @@ using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Chapters;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
@@ -173,6 +172,8 @@ namespace Emby.Server.Implementations
|
||||
/// </summary>
|
||||
protected ILogger<ApplicationHost> Logger { get; }
|
||||
|
||||
protected IServiceCollection ServiceCollection { get; }
|
||||
|
||||
private IPlugin[] _plugins;
|
||||
|
||||
/// <summary>
|
||||
@@ -238,9 +239,11 @@ namespace Emby.Server.Implementations
|
||||
ILoggerFactory loggerFactory,
|
||||
IStartupOptions options,
|
||||
IFileSystem fileSystem,
|
||||
INetworkManager networkManager)
|
||||
INetworkManager networkManager,
|
||||
IServiceCollection serviceCollection)
|
||||
{
|
||||
_xmlSerializer = new MyXmlSerializer();
|
||||
ServiceCollection = serviceCollection;
|
||||
|
||||
_networkManager = networkManager;
|
||||
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
|
||||
@@ -464,7 +467,7 @@ namespace Emby.Server.Implementations
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Init(IServiceCollection serviceCollection)
|
||||
public void Init()
|
||||
{
|
||||
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
|
||||
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
|
||||
@@ -493,7 +496,7 @@ namespace Emby.Server.Implementations
|
||||
|
||||
DiscoverTypes();
|
||||
|
||||
RegisterServices(serviceCollection);
|
||||
RegisterServices();
|
||||
}
|
||||
|
||||
public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
|
||||
@@ -502,139 +505,139 @@ namespace Emby.Server.Implementations
|
||||
/// <summary>
|
||||
/// Registers services/resources with the service collection that will be available via DI.
|
||||
/// </summary>
|
||||
protected virtual void RegisterServices(IServiceCollection serviceCollection)
|
||||
protected virtual void RegisterServices()
|
||||
{
|
||||
serviceCollection.AddSingleton(_startupOptions);
|
||||
ServiceCollection.AddSingleton(_startupOptions);
|
||||
|
||||
serviceCollection.AddMemoryCache();
|
||||
ServiceCollection.AddMemoryCache();
|
||||
|
||||
serviceCollection.AddSingleton(ConfigurationManager);
|
||||
serviceCollection.AddSingleton<IApplicationHost>(this);
|
||||
ServiceCollection.AddSingleton(ConfigurationManager);
|
||||
ServiceCollection.AddSingleton<IApplicationHost>(this);
|
||||
|
||||
serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
||||
ServiceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
|
||||
|
||||
serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
|
||||
ServiceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
|
||||
|
||||
serviceCollection.AddSingleton(_fileSystemManager);
|
||||
serviceCollection.AddSingleton<TvdbClientManager>();
|
||||
ServiceCollection.AddSingleton(_fileSystemManager);
|
||||
ServiceCollection.AddSingleton<TvdbClientManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
|
||||
ServiceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
|
||||
|
||||
serviceCollection.AddSingleton(_networkManager);
|
||||
ServiceCollection.AddSingleton(_networkManager);
|
||||
|
||||
serviceCollection.AddSingleton<IIsoManager, IsoManager>();
|
||||
ServiceCollection.AddSingleton<IIsoManager, IsoManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ITaskManager, TaskManager>();
|
||||
ServiceCollection.AddSingleton<ITaskManager, TaskManager>();
|
||||
|
||||
serviceCollection.AddSingleton(_xmlSerializer);
|
||||
ServiceCollection.AddSingleton(_xmlSerializer);
|
||||
|
||||
serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
|
||||
ServiceCollection.AddSingleton<IStreamHelper, StreamHelper>();
|
||||
|
||||
serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
|
||||
ServiceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
|
||||
|
||||
serviceCollection.AddSingleton<ISocketFactory, SocketFactory>();
|
||||
ServiceCollection.AddSingleton<ISocketFactory, SocketFactory>();
|
||||
|
||||
serviceCollection.AddSingleton<IInstallationManager, InstallationManager>();
|
||||
ServiceCollection.AddSingleton<IInstallationManager, InstallationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IZipClient, ZipClient>();
|
||||
ServiceCollection.AddSingleton<IZipClient, ZipClient>();
|
||||
|
||||
serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
|
||||
ServiceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
|
||||
|
||||
serviceCollection.AddSingleton<IServerApplicationHost>(this);
|
||||
serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
|
||||
ServiceCollection.AddSingleton<IServerApplicationHost>(this);
|
||||
ServiceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
|
||||
|
||||
serviceCollection.AddSingleton(ServerConfigurationManager);
|
||||
ServiceCollection.AddSingleton(ServerConfigurationManager);
|
||||
|
||||
serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
||||
ServiceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
||||
ServiceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
||||
|
||||
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
||||
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
||||
ServiceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
||||
ServiceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
||||
ServiceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
|
||||
|
||||
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
||||
ServiceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
|
||||
ServiceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
|
||||
serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
|
||||
ServiceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
|
||||
ServiceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
|
||||
serviceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
|
||||
serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
|
||||
serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
|
||||
ServiceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
|
||||
ServiceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
|
||||
ServiceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
|
||||
ServiceCollection.AddSingleton<ILibraryManager, LibraryManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IMusicManager, MusicManager>();
|
||||
ServiceCollection.AddSingleton<IMusicManager, MusicManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
|
||||
ServiceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
|
||||
|
||||
serviceCollection.AddSingleton<ISearchEngine, SearchEngine>();
|
||||
ServiceCollection.AddSingleton<ISearchEngine, SearchEngine>();
|
||||
|
||||
serviceCollection.AddSingleton<ServiceController>();
|
||||
serviceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
|
||||
ServiceCollection.AddSingleton<ServiceController>();
|
||||
ServiceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
|
||||
|
||||
serviceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
|
||||
ServiceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
|
||||
|
||||
serviceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
|
||||
ServiceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
||||
ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
|
||||
ServiceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
|
||||
ServiceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IProviderManager, ProviderManager>();
|
||||
ServiceCollection.AddSingleton<IProviderManager, ProviderManager>();
|
||||
|
||||
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
|
||||
serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
|
||||
serviceCollection.AddSingleton<IDtoService, DtoService>();
|
||||
ServiceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
|
||||
ServiceCollection.AddSingleton<IDtoService, DtoService>();
|
||||
|
||||
serviceCollection.AddSingleton<IChannelManager, ChannelManager>();
|
||||
ServiceCollection.AddSingleton<IChannelManager, ChannelManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
||||
ServiceCollection.AddSingleton<ISessionManager, SessionManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
||||
ServiceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
||||
ServiceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
||||
ServiceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>();
|
||||
ServiceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>();
|
||||
|
||||
serviceCollection.AddSingleton<LiveTvDtoService>();
|
||||
serviceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
|
||||
ServiceCollection.AddSingleton<LiveTvDtoService>();
|
||||
ServiceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
||||
ServiceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
||||
|
||||
serviceCollection.AddSingleton<INotificationManager, NotificationManager>();
|
||||
ServiceCollection.AddSingleton<INotificationManager, NotificationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
||||
ServiceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
||||
|
||||
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
||||
ServiceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
||||
ServiceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
||||
serviceCollection.AddSingleton<ISessionContext, SessionContext>();
|
||||
ServiceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
|
||||
ServiceCollection.AddSingleton<ISessionContext, SessionContext>();
|
||||
|
||||
serviceCollection.AddSingleton<IAuthService, AuthService>();
|
||||
ServiceCollection.AddSingleton<IAuthService, AuthService>();
|
||||
|
||||
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
|
||||
ServiceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
|
||||
|
||||
serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
|
||||
serviceCollection.AddSingleton<EncodingHelper>();
|
||||
ServiceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
|
||||
ServiceCollection.AddSingleton<EncodingHelper>();
|
||||
|
||||
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
|
||||
ServiceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
|
||||
|
||||
serviceCollection.AddSingleton<TranscodingJobHelper>();
|
||||
serviceCollection.AddScoped<MediaInfoHelper>();
|
||||
serviceCollection.AddScoped<AudioHelper>();
|
||||
serviceCollection.AddScoped<DynamicHlsHelper>();
|
||||
ServiceCollection.AddSingleton<TranscodingJobHelper>();
|
||||
ServiceCollection.AddScoped<MediaInfoHelper>();
|
||||
ServiceCollection.AddScoped<AudioHelper>();
|
||||
ServiceCollection.AddScoped<DynamicHlsHelper>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -834,6 +837,8 @@ namespace Emby.Server.Implementations
|
||||
{
|
||||
hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
|
||||
}
|
||||
|
||||
plugin.RegisterServices(ServiceCollection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -2,11 +2,11 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Emby.Server.Implementations.AppBase;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -90,9 +90,6 @@ namespace Emby.Server.Implementations.Data
|
||||
_typeMapper = new TypeMapper();
|
||||
_jsonOptions = JsonDefaults.GetOptions();
|
||||
|
||||
// GetItem throws NotSupportedException with this enabled, so hardcode false.
|
||||
_jsonOptions.IgnoreNullValues = false;
|
||||
|
||||
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.Devices;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
@@ -7,11 +7,11 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mono.Nat;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
@@ -15,7 +16,6 @@ using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
@@ -43,22 +44,22 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
|
||||
private async void OnLiveTvManagerSeriesTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||
{
|
||||
await SendMessage("SeriesTimerCreated", e.Argument).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
|
||||
private async void OnLiveTvManagerTimerCreated(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||
{
|
||||
await SendMessage("TimerCreated", e.Argument).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
|
||||
private async void OnLiveTvManagerSeriesTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||
{
|
||||
await SendMessage("SeriesTimerCancelled", e.Argument).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)
|
||||
private async void OnLiveTvManagerTimerCancelled(object sender, GenericEventArgs<TimerEventInfo> e)
|
||||
{
|
||||
await SendMessage("TimerCancelled", e.Argument).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Updates;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Class WebSocketEvents.
|
||||
/// </summary>
|
||||
public class ServerEventNotifier : IServerEntryPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The user manager.
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The installation manager.
|
||||
/// </summary>
|
||||
private readonly IInstallationManager _installationManager;
|
||||
|
||||
/// <summary>
|
||||
/// The kernel.
|
||||
/// </summary>
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
|
||||
/// <summary>
|
||||
/// The task manager.
|
||||
/// </summary>
|
||||
private readonly ITaskManager _taskManager;
|
||||
|
||||
private readonly ISessionManager _sessionManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerEventNotifier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The application host.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="installationManager">The installation manager.</param>
|
||||
/// <param name="taskManager">The task manager.</param>
|
||||
/// <param name="sessionManager">The session manager.</param>
|
||||
public ServerEventNotifier(
|
||||
IServerApplicationHost appHost,
|
||||
IUserManager userManager,
|
||||
IInstallationManager installationManager,
|
||||
ITaskManager taskManager,
|
||||
ISessionManager sessionManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_installationManager = installationManager;
|
||||
_appHost = appHost;
|
||||
_taskManager = taskManager;
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RunAsync()
|
||||
{
|
||||
_userManager.OnUserDeleted += OnUserDeleted;
|
||||
_userManager.OnUserUpdated += OnUserUpdated;
|
||||
|
||||
_appHost.HasPendingRestartChanged += OnHasPendingRestartChanged;
|
||||
|
||||
_installationManager.PluginUninstalled += OnPluginUninstalled;
|
||||
_installationManager.PackageInstalling += OnPackageInstalling;
|
||||
_installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled;
|
||||
_installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted;
|
||||
_installationManager.PackageInstallationFailed += OnPackageInstallationFailed;
|
||||
|
||||
_taskManager.TaskCompleted += OnTaskCompleted;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnPackageInstalling(object sender, InstallationInfo e)
|
||||
{
|
||||
await SendMessageToAdminSessions("PackageInstalling", e).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPackageInstallationCancelled(object sender, InstallationInfo e)
|
||||
{
|
||||
await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPackageInstallationCompleted(object sender, InstallationInfo e)
|
||||
{
|
||||
await SendMessageToAdminSessions("PackageInstallationCompleted", e).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e)
|
||||
{
|
||||
await SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
|
||||
{
|
||||
await SendMessageToAdminSessions("ScheduledTaskEnded", e.Result).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Installations the manager_ plugin uninstalled.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The e.</param>
|
||||
private async void OnPluginUninstalled(object sender, IPlugin e)
|
||||
{
|
||||
await SendMessageToAdminSessions("PluginUninstalled", e).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the HasPendingRestartChanged event of the kernel control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||
private async void OnHasPendingRestartChanged(object sender, EventArgs e)
|
||||
{
|
||||
await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Users the manager_ user updated.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The e.</param>
|
||||
private async void OnUserUpdated(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
var dto = _userManager.GetUserDto(e.Argument);
|
||||
|
||||
await SendMessageToUserSession(e.Argument, "UserUpdated", dto).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Users the manager_ user deleted.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The e.</param>
|
||||
private async void OnUserDeleted(object sender, GenericEventArgs<User> e)
|
||||
{
|
||||
await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task SendMessageToAdminSessions<T>(string name, T data)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _sessionManager.SendMessageToAdminSessions(name, data, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendMessageToUserSession<T>(User user, string name, T data)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _sessionManager.SendMessageToUserSessions(
|
||||
new List<Guid> { user.Id },
|
||||
name,
|
||||
data,
|
||||
CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool dispose)
|
||||
{
|
||||
if (dispose)
|
||||
{
|
||||
_userManager.OnUserDeleted -= OnUserDeleted;
|
||||
_userManager.OnUserUpdated -= OnUserUpdated;
|
||||
|
||||
_installationManager.PluginUninstalled -= OnPluginUninstalled;
|
||||
_installationManager.PackageInstalling -= OnPackageInstalling;
|
||||
_installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled;
|
||||
_installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted;
|
||||
_installationManager.PackageInstallationFailed -= OnPackageInstallationFailed;
|
||||
|
||||
_appHost.HasPendingRestartChanged -= OnHasPendingRestartChanged;
|
||||
|
||||
_taskManager.TaskCompleted -= OnTaskCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,13 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Server.Implementations.Services;
|
||||
using Emby.Server.Implementations.SocketSharp;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Services;
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
return;
|
||||
}
|
||||
|
||||
WebSocketMessage<object> stub;
|
||||
WebSocketMessage<object>? stub;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -209,6 +209,12 @@ namespace Emby.Server.Implementations.HttpServer
|
||||
return;
|
||||
}
|
||||
|
||||
if (stub == null)
|
||||
{
|
||||
_logger.LogError("Error processing web socket message");
|
||||
return;
|
||||
}
|
||||
|
||||
// Tell the PipeReader how much of the buffer we have consumed
|
||||
reader.AdvanceTo(buffer.End);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
@@ -29,7 +30,6 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
|
||||
@@ -5,8 +5,8 @@ using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using Emby.Server.Implementations.Library;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
@@ -24,7 +25,6 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Sorting;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"HeaderContinueWatching": "Lanjutkan Menonton",
|
||||
"HeaderCameraUploads": "Unggahan Kamera",
|
||||
"HeaderAlbumArtists": "Album Artis",
|
||||
"Genres": "Genre",
|
||||
"Genres": "Aliran",
|
||||
"Folders": "Folder",
|
||||
"Favorites": "Favorit",
|
||||
"Collections": "Koleksi",
|
||||
|
||||
@@ -69,5 +69,8 @@
|
||||
"AppDeviceValues": "App: {0}, อุปกรณ์: {1}",
|
||||
"Albums": "อัลบั้ม",
|
||||
"ScheduledTaskStartedWithName": "{0} เริ่มต้น",
|
||||
"ScheduledTaskFailedWithName": "{0} ล้มเหลว"
|
||||
"ScheduledTaskFailedWithName": "{0} ล้มเหลว",
|
||||
"Songs": "เพลง",
|
||||
"Shows": "แสดง",
|
||||
"ServerNameNeedsToBeRestarted": "{0} ต้องการรีสตาร์ท"
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -5,8 +5,8 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller;
|
||||
@@ -17,6 +18,8 @@ using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Events.Session;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Security;
|
||||
@@ -24,7 +27,6 @@ using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Devices;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Session;
|
||||
@@ -40,25 +42,16 @@ namespace Emby.Server.Implementations.Session
|
||||
/// </summary>
|
||||
public class SessionManager : ISessionManager, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The user data repository.
|
||||
/// </summary>
|
||||
private readonly IUserDataManager _userDataManager;
|
||||
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
private readonly ILogger<SessionManager> _logger;
|
||||
|
||||
private readonly IEventManager _eventManager;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly IMusicManager _musicManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
|
||||
private readonly IAuthenticationRepository _authRepo;
|
||||
private readonly IDeviceManager _deviceManager;
|
||||
|
||||
@@ -75,6 +68,7 @@ namespace Emby.Server.Implementations.Session
|
||||
|
||||
public SessionManager(
|
||||
ILogger<SessionManager> logger,
|
||||
IEventManager eventManager,
|
||||
IUserDataManager userDataManager,
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
@@ -87,6 +81,7 @@ namespace Emby.Server.Implementations.Session
|
||||
IMediaSourceManager mediaSourceManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_eventManager = eventManager;
|
||||
_userDataManager = userDataManager;
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
@@ -209,6 +204,8 @@ namespace Emby.Server.Implementations.Session
|
||||
}
|
||||
}
|
||||
|
||||
_eventManager.Publish(new SessionStartedEventArgs(info));
|
||||
|
||||
EventHelper.QueueEventIfNotNull(
|
||||
SessionStarted,
|
||||
this,
|
||||
@@ -230,6 +227,8 @@ namespace Emby.Server.Implementations.Session
|
||||
},
|
||||
_logger);
|
||||
|
||||
_eventManager.Publish(new SessionEndedEventArgs(info));
|
||||
|
||||
info.Dispose();
|
||||
}
|
||||
|
||||
@@ -667,22 +666,26 @@ namespace Emby.Server.Implementations.Session
|
||||
}
|
||||
}
|
||||
|
||||
var eventArgs = new PlaybackProgressEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
MediaSourceId = info.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
Session = session
|
||||
};
|
||||
|
||||
await _eventManager.PublishAsync(eventArgs).ConfigureAwait(false);
|
||||
|
||||
// Nothing to save here
|
||||
// Fire events to inform plugins
|
||||
EventHelper.QueueEventIfNotNull(
|
||||
PlaybackStart,
|
||||
this,
|
||||
new PlaybackProgressEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
MediaSourceId = info.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
Session = session
|
||||
},
|
||||
eventArgs,
|
||||
_logger);
|
||||
|
||||
StartIdleCheckTimer();
|
||||
@@ -750,23 +753,25 @@ namespace Emby.Server.Implementations.Session
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackProgress?.Invoke(
|
||||
this,
|
||||
new PlaybackProgressEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
PlaybackPositionTicks = session.PlayState.PositionTicks,
|
||||
MediaSourceId = session.PlayState.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
IsPaused = info.IsPaused,
|
||||
PlaySessionId = info.PlaySessionId,
|
||||
IsAutomated = isAutomated,
|
||||
Session = session
|
||||
});
|
||||
var eventArgs = new PlaybackProgressEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
PlaybackPositionTicks = session.PlayState.PositionTicks,
|
||||
MediaSourceId = session.PlayState.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
IsPaused = info.IsPaused,
|
||||
PlaySessionId = info.PlaySessionId,
|
||||
IsAutomated = isAutomated,
|
||||
Session = session
|
||||
};
|
||||
|
||||
await _eventManager.PublishAsync(eventArgs).ConfigureAwait(false);
|
||||
|
||||
PlaybackProgress?.Invoke(this, eventArgs);
|
||||
|
||||
if (!isAutomated)
|
||||
{
|
||||
@@ -943,23 +948,23 @@ namespace Emby.Server.Implementations.Session
|
||||
}
|
||||
}
|
||||
|
||||
EventHelper.QueueEventIfNotNull(
|
||||
PlaybackStopped,
|
||||
this,
|
||||
new PlaybackStopEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
PlaybackPositionTicks = info.PositionTicks,
|
||||
PlayedToCompletion = playedToCompletion,
|
||||
MediaSourceId = info.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
Session = session
|
||||
},
|
||||
_logger);
|
||||
var eventArgs = new PlaybackStopEventArgs
|
||||
{
|
||||
Item = libraryItem,
|
||||
Users = users,
|
||||
PlaybackPositionTicks = info.PositionTicks,
|
||||
PlayedToCompletion = playedToCompletion,
|
||||
MediaSourceId = info.MediaSourceId,
|
||||
MediaInfo = info.Item,
|
||||
DeviceName = session.DeviceName,
|
||||
ClientName = session.Client,
|
||||
DeviceId = session.DeviceId,
|
||||
Session = session
|
||||
};
|
||||
|
||||
await _eventManager.PublishAsync(eventArgs).ConfigureAwait(false);
|
||||
|
||||
EventHelper.QueueEventIfNotNull(PlaybackStopped, this, eventArgs, _logger);
|
||||
}
|
||||
|
||||
private bool OnPlaybackStopped(User user, BaseItem item, long? positionTicks, bool playbackFailed)
|
||||
|
||||
@@ -4,9 +4,9 @@ using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
Reference in New Issue
Block a user