mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Apply review suggestions
This commit is contained in:
parent
bac4bf96a0
commit
511d20a100
@ -8,7 +8,6 @@ using Jellyfin.Data.Entities;
|
|||||||
using MediaBrowser.Common.Plugins;
|
using MediaBrowser.Common.Plugins;
|
||||||
using MediaBrowser.Common.Updates;
|
using MediaBrowser.Common.Updates;
|
||||||
using MediaBrowser.Controller.Authentication;
|
using MediaBrowser.Controller.Authentication;
|
||||||
using MediaBrowser.Controller.Devices;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
@ -30,7 +29,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ActivityLogEntryPoint : IServerEntryPoint
|
public sealed class ActivityLogEntryPoint : IServerEntryPoint
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger<ActivityLogEntryPoint> _logger;
|
||||||
private readonly IInstallationManager _installationManager;
|
private readonly IInstallationManager _installationManager;
|
||||||
private readonly ISessionManager _sessionManager;
|
private readonly ISessionManager _sessionManager;
|
||||||
private readonly ITaskManager _taskManager;
|
private readonly ITaskManager _taskManager;
|
||||||
@ -38,14 +37,12 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly ISubtitleManager _subManager;
|
private readonly ISubtitleManager _subManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDeviceManager _deviceManager;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ActivityLogEntryPoint"/> class.
|
/// Initializes a new instance of the <see cref="ActivityLogEntryPoint"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="sessionManager">The session manager.</param>
|
/// <param name="sessionManager">The session manager.</param>
|
||||||
/// <param name="deviceManager">The device manager.</param>
|
|
||||||
/// <param name="taskManager">The task manager.</param>
|
/// <param name="taskManager">The task manager.</param>
|
||||||
/// <param name="activityManager">The activity manager.</param>
|
/// <param name="activityManager">The activity manager.</param>
|
||||||
/// <param name="localization">The localization manager.</param>
|
/// <param name="localization">The localization manager.</param>
|
||||||
@ -55,7 +52,6 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
public ActivityLogEntryPoint(
|
public ActivityLogEntryPoint(
|
||||||
ILogger<ActivityLogEntryPoint> logger,
|
ILogger<ActivityLogEntryPoint> logger,
|
||||||
ISessionManager sessionManager,
|
ISessionManager sessionManager,
|
||||||
IDeviceManager deviceManager,
|
|
||||||
ITaskManager taskManager,
|
ITaskManager taskManager,
|
||||||
IActivityManager activityManager,
|
IActivityManager activityManager,
|
||||||
ILocalizationManager localization,
|
ILocalizationManager localization,
|
||||||
@ -65,7 +61,6 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
_deviceManager = deviceManager;
|
|
||||||
_taskManager = taskManager;
|
_taskManager = taskManager;
|
||||||
_activityManager = activityManager;
|
_activityManager = activityManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
@ -99,25 +94,9 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_userManager.UserPolicyUpdated += OnUserPolicyUpdated;
|
_userManager.UserPolicyUpdated += OnUserPolicyUpdated;
|
||||||
_userManager.UserLockedOut += OnUserLockedOut;
|
_userManager.UserLockedOut += OnUserLockedOut;
|
||||||
|
|
||||||
_deviceManager.CameraImageUploaded += OnCameraImageUploaded;
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnCameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
|
|
||||||
{
|
|
||||||
await CreateLogEntry(new ActivityLog(
|
|
||||||
string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
_localization.GetLocalizedString("CameraImageUploadedFrom"),
|
|
||||||
e.Argument.Device.Name),
|
|
||||||
NotificationType.CameraImageUploaded.ToString(),
|
|
||||||
Guid.Empty,
|
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||||
{
|
{
|
||||||
await CreateLogEntry(new ActivityLog(
|
await CreateLogEntry(new ActivityLog(
|
||||||
@ -126,9 +105,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("UserLockedOutWithName"),
|
_localization.GetLocalizedString("UserLockedOutWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
NotificationType.UserLockedOut.ToString(),
|
NotificationType.UserLockedOut.ToString(),
|
||||||
e.Argument.Id,
|
e.Argument.Id))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,11 +116,9 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
|
_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"),
|
||||||
e.Provider,
|
e.Provider,
|
||||||
Emby.Notifications.NotificationEntryPoint.GetItemName(e.Item)),
|
Notifications.NotificationEntryPoint.GetItemName(e.Item)),
|
||||||
"SubtitleDownloadFailure",
|
"SubtitleDownloadFailure",
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture),
|
ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture),
|
||||||
ShortOverview = e.Exception.Message
|
ShortOverview = e.Exception.Message
|
||||||
@ -181,9 +156,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
GetItemName(item),
|
GetItemName(item),
|
||||||
e.DeviceName),
|
e.DeviceName),
|
||||||
GetPlaybackStoppedNotificationType(item.MediaType),
|
GetPlaybackStoppedNotificationType(item.MediaType),
|
||||||
user.Id,
|
user.Id))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,9 +191,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
GetItemName(item),
|
GetItemName(item),
|
||||||
e.DeviceName),
|
e.DeviceName),
|
||||||
GetPlaybackNotificationType(item.MediaType),
|
GetPlaybackNotificationType(item.MediaType),
|
||||||
user.Id,
|
user.Id))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,9 +258,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
session.UserName,
|
session.UserName,
|
||||||
session.DeviceName),
|
session.DeviceName),
|
||||||
"SessionEnded",
|
"SessionEnded",
|
||||||
session.UserId,
|
session.UserId)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -308,9 +277,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("AuthenticationSucceededWithUserName"),
|
_localization.GetLocalizedString("AuthenticationSucceededWithUserName"),
|
||||||
user.Name),
|
user.Name),
|
||||||
"AuthenticationSucceeded",
|
"AuthenticationSucceeded",
|
||||||
user.Id,
|
user.Id)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -327,10 +294,9 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("FailedLoginAttemptWithUserName"),
|
_localization.GetLocalizedString("FailedLoginAttemptWithUserName"),
|
||||||
e.Argument.Username),
|
e.Argument.Username),
|
||||||
"AuthenticationFailed",
|
"AuthenticationFailed",
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Error)
|
|
||||||
{
|
{
|
||||||
|
LogSeverity = LogLevel.Error,
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
_localization.GetLocalizedString("LabelIpAddressValue"),
|
_localization.GetLocalizedString("LabelIpAddressValue"),
|
||||||
@ -346,9 +312,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("UserPolicyUpdatedWithName"),
|
_localization.GetLocalizedString("UserPolicyUpdatedWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
"UserPolicyUpdated",
|
"UserPolicyUpdated",
|
||||||
e.Argument.Id,
|
e.Argument.Id))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,9 +324,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("UserDeletedWithName"),
|
_localization.GetLocalizedString("UserDeletedWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
"UserDeleted",
|
"UserDeleted",
|
||||||
Guid.Empty,
|
Guid.Empty))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,9 +336,8 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("UserPasswordChangedWithName"),
|
_localization.GetLocalizedString("UserPasswordChangedWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
"UserPasswordChanged",
|
"UserPasswordChanged",
|
||||||
e.Argument.Id,
|
e.Argument.Id))
|
||||||
DateTime.UtcNow,
|
.ConfigureAwait(false);
|
||||||
LogLevel.Trace)).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
|
||||||
@ -387,9 +348,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("UserCreatedWithName"),
|
_localization.GetLocalizedString("UserCreatedWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
"UserCreated",
|
"UserCreated",
|
||||||
e.Argument.Id,
|
e.Argument.Id))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,9 +368,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
session.UserName,
|
session.UserName,
|
||||||
session.DeviceName),
|
session.DeviceName),
|
||||||
"SessionStarted",
|
"SessionStarted",
|
||||||
session.UserId,
|
session.UserId)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -428,9 +385,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("PluginUpdatedWithName"),
|
_localization.GetLocalizedString("PluginUpdatedWithName"),
|
||||||
e.Argument.Item1.Name),
|
e.Argument.Item1.Name),
|
||||||
NotificationType.PluginUpdateInstalled.ToString(),
|
NotificationType.PluginUpdateInstalled.ToString(),
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -448,9 +403,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("PluginUninstalledWithName"),
|
_localization.GetLocalizedString("PluginUninstalledWithName"),
|
||||||
e.Argument.Name),
|
e.Argument.Name),
|
||||||
NotificationType.PluginUninstalled.ToString(),
|
NotificationType.PluginUninstalled.ToString(),
|
||||||
Guid.Empty,
|
Guid.Empty))
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace))
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,9 +415,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("PluginInstalledWithName"),
|
_localization.GetLocalizedString("PluginInstalledWithName"),
|
||||||
e.Argument.name),
|
e.Argument.name),
|
||||||
NotificationType.PluginInstalled.ToString(),
|
NotificationType.PluginInstalled.ToString(),
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -483,9 +434,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_localization.GetLocalizedString("NameInstallFailed"),
|
_localization.GetLocalizedString("NameInstallFailed"),
|
||||||
installationInfo.Name),
|
installationInfo.Name),
|
||||||
NotificationType.InstallationFailed.ToString(),
|
NotificationType.InstallationFailed.ToString(),
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(
|
ShortOverview = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
@ -529,10 +478,9 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
await CreateLogEntry(new ActivityLog(
|
await CreateLogEntry(new ActivityLog(
|
||||||
string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
|
||||||
NotificationType.TaskFailed.ToString(),
|
NotificationType.TaskFailed.ToString(),
|
||||||
Guid.Empty,
|
Guid.Empty)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Error)
|
|
||||||
{
|
{
|
||||||
|
LogSeverity = LogLevel.Error,
|
||||||
Overview = string.Join(Environment.NewLine, vals),
|
Overview = string.Join(Environment.NewLine, vals),
|
||||||
ShortOverview = runningTime
|
ShortOverview = runningTime
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
@ -567,8 +515,6 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
_userManager.UserDeleted -= OnUserDeleted;
|
_userManager.UserDeleted -= OnUserDeleted;
|
||||||
_userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
|
_userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
|
||||||
_userManager.UserLockedOut -= OnUserLockedOut;
|
_userManager.UserLockedOut -= OnUserLockedOut;
|
||||||
|
|
||||||
_deviceManager.CameraImageUploaded -= OnCameraImageUploaded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -588,7 +534,7 @@ namespace Emby.Server.Implementations.Activity
|
|||||||
{
|
{
|
||||||
int years = days / DaysInYear;
|
int years = days / DaysInYear;
|
||||||
values.Add(CreateValueString(years, "year"));
|
values.Add(CreateValueString(years, "year"));
|
||||||
days = days % DaysInYear;
|
days %= DaysInYear;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of months
|
// Number of months
|
||||||
|
@ -34,7 +34,6 @@ namespace Emby.Server.Implementations.Devices
|
|||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ILibraryMonitor _libraryMonitor;
|
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILocalizationManager _localizationManager;
|
private readonly ILocalizationManager _localizationManager;
|
||||||
@ -43,9 +42,6 @@ namespace Emby.Server.Implementations.Devices
|
|||||||
|
|
||||||
public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||||
|
|
||||||
public event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
|
||||||
|
|
||||||
private readonly object _cameraUploadSyncLock = new object();
|
|
||||||
private readonly object _capabilitiesSyncLock = new object();
|
private readonly object _capabilitiesSyncLock = new object();
|
||||||
|
|
||||||
public DeviceManager(
|
public DeviceManager(
|
||||||
@ -55,13 +51,11 @@ namespace Emby.Server.Implementations.Devices
|
|||||||
ILocalizationManager localizationManager,
|
ILocalizationManager localizationManager,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
ILibraryMonitor libraryMonitor,
|
|
||||||
IServerConfigurationManager config)
|
IServerConfigurationManager config)
|
||||||
{
|
{
|
||||||
_json = json;
|
_json = json;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_libraryMonitor = libraryMonitor;
|
|
||||||
_config = config;
|
_config = config;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_localizationManager = localizationManager;
|
_localizationManager = localizationManager;
|
||||||
@ -194,105 +188,6 @@ namespace Emby.Server.Implementations.Devices
|
|||||||
return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N", CultureInfo.InvariantCulture));
|
return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N", CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContentUploadHistory GetCameraUploadHistory(string deviceId)
|
|
||||||
{
|
|
||||||
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
|
|
||||||
|
|
||||||
lock (_cameraUploadSyncLock)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return _json.DeserializeFromFile<ContentUploadHistory>(path);
|
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
return new ContentUploadHistory
|
|
||||||
{
|
|
||||||
DeviceId = deviceId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file)
|
|
||||||
{
|
|
||||||
var device = GetDevice(deviceId, false);
|
|
||||||
var uploadPathInfo = GetUploadPath(device);
|
|
||||||
|
|
||||||
var path = uploadPathInfo.Item1;
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(file.Album))
|
|
||||||
{
|
|
||||||
path = Path.Combine(path, _fileSystem.GetValidFilename(file.Album));
|
|
||||||
}
|
|
||||||
|
|
||||||
path = Path.Combine(path, file.Name);
|
|
||||||
path = Path.ChangeExtension(path, MimeTypes.ToExtension(file.MimeType) ?? "jpg");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
||||||
|
|
||||||
await EnsureLibraryFolder(uploadPathInfo.Item2, uploadPathInfo.Item3).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_libraryMonitor.ReportFileSystemChangeBeginning(path);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
||||||
{
|
|
||||||
await stream.CopyToAsync(fs).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddCameraUpload(deviceId, file);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_libraryMonitor.ReportFileSystemChangeComplete(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CameraImageUploaded != null)
|
|
||||||
{
|
|
||||||
CameraImageUploaded?.Invoke(this, new GenericEventArgs<CameraImageUploadInfo>
|
|
||||||
{
|
|
||||||
Argument = new CameraImageUploadInfo
|
|
||||||
{
|
|
||||||
Device = device,
|
|
||||||
FileInfo = file
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddCameraUpload(string deviceId, LocalFileInfo file)
|
|
||||||
{
|
|
||||||
var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
||||||
|
|
||||||
lock (_cameraUploadSyncLock)
|
|
||||||
{
|
|
||||||
ContentUploadHistory history;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
history = _json.DeserializeFromFile<ContentUploadHistory>(path);
|
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
history = new ContentUploadHistory
|
|
||||||
{
|
|
||||||
DeviceId = deviceId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
history.DeviceId = deviceId;
|
|
||||||
|
|
||||||
var list = history.FilesUploaded.ToList();
|
|
||||||
list.Add(file);
|
|
||||||
history.FilesUploaded = list.ToArray();
|
|
||||||
|
|
||||||
_json.SerializeToFile(history, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Task EnsureLibraryFolder(string path, string name)
|
internal Task EnsureLibraryFolder(string path, string name)
|
||||||
{
|
{
|
||||||
var existingFolders = _libraryManager
|
var existingFolders = _libraryManager
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Jellyfin.Data.Entities
|
namespace Jellyfin.Data.Entities
|
||||||
{
|
{
|
||||||
[Table("ActivityLog")]
|
|
||||||
public partial class ActivityLog
|
public partial class ActivityLog
|
||||||
{
|
{
|
||||||
partial void Init();
|
partial void Init();
|
||||||
@ -35,23 +30,26 @@ namespace Jellyfin.Data.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="userid"></param>
|
/// <param name="userId"></param>
|
||||||
/// <param name="datecreated"></param>
|
/// <param name="datecreated"></param>
|
||||||
/// <param name="logseverity"></param>
|
/// <param name="logSeverity"></param>
|
||||||
public ActivityLog(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity)
|
public ActivityLog(string name, string type, Guid userId)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(type))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(type));
|
||||||
|
}
|
||||||
|
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(type)) throw new ArgumentNullException(nameof(type));
|
|
||||||
this.Type = type;
|
this.Type = type;
|
||||||
|
this.UserId = userId;
|
||||||
this.UserId = userid;
|
this.DateCreated = DateTime.UtcNow;
|
||||||
|
this.LogSeverity = LogLevel.Trace;
|
||||||
this.DateCreated = datecreated;
|
|
||||||
|
|
||||||
this.LogSeverity = logseverity;
|
|
||||||
|
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
@ -61,12 +59,12 @@ namespace Jellyfin.Data.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <param name="userid"></param>
|
/// <param name="userId"></param>
|
||||||
/// <param name="datecreated"></param>
|
/// <param name="datecreated"></param>
|
||||||
/// <param name="logseverity"></param>
|
/// <param name="logseverity"></param>
|
||||||
public static ActivityLog Create(string name, string type, Guid userid, DateTime datecreated, Microsoft.Extensions.Logging.LogLevel logseverity)
|
public static ActivityLog Create(string name, string type, Guid userId)
|
||||||
{
|
{
|
||||||
return new ActivityLog(name, type, userid, datecreated, logseverity);
|
return new ActivityLog(name, type, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@ -134,10 +132,10 @@ namespace Jellyfin.Data.Entities
|
|||||||
/// Required
|
/// Required
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Required]
|
[Required]
|
||||||
public Microsoft.Extensions.Logging.LogLevel LogSeverity { get; set; }
|
public LogLevel LogSeverity { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required, ConcurrenyToken
|
/// Required, ConcurrencyToken.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ConcurrencyCheck]
|
[ConcurrencyCheck]
|
||||||
[Required]
|
[Required]
|
||||||
@ -147,7 +145,6 @@ namespace Jellyfin.Data.Entities
|
|||||||
{
|
{
|
||||||
RowVersion++;
|
RowVersion++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Jellyfin.Server.Implementations.Activity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ActivityManager : IActivityManager
|
public class ActivityManager : IActivityManager
|
||||||
{
|
{
|
||||||
private JellyfinDbProvider _provider;
|
private readonly JellyfinDbProvider _provider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ActivityManager"/> class.
|
/// Initializes a new instance of the <see cref="ActivityManager"/> class.
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma warning disable CS1591
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Emby.Server.Implementations.Data;
|
using Emby.Server.Implementations.Data;
|
||||||
using Jellyfin.Data.Entities;
|
using Jellyfin.Data.Entities;
|
||||||
@ -12,6 +11,9 @@ using SQLitePCL.pretty;
|
|||||||
|
|
||||||
namespace Jellyfin.Server.Migrations.Routines
|
namespace Jellyfin.Server.Migrations.Routines
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The migration routine for migrating the activity log database to EF Core.
|
||||||
|
/// </summary>
|
||||||
public class MigrateActivityLogDb : IMigrationRoutine
|
public class MigrateActivityLogDb : IMigrationRoutine
|
||||||
{
|
{
|
||||||
private const string DbFilename = "activitylog.db";
|
private const string DbFilename = "activitylog.db";
|
||||||
@ -20,6 +22,12 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
private readonly JellyfinDbProvider _provider;
|
private readonly JellyfinDbProvider _provider;
|
||||||
private readonly IServerApplicationPaths _paths;
|
private readonly IServerApplicationPaths _paths;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MigrateActivityLogDb"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger">The logger.</param>
|
||||||
|
/// <param name="paths">The server application paths.</param>
|
||||||
|
/// <param name="provider">The database provider.</param>
|
||||||
public MigrateActivityLogDb(ILogger<MigrateActivityLogDb> logger, IServerApplicationPaths paths, JellyfinDbProvider provider)
|
public MigrateActivityLogDb(ILogger<MigrateActivityLogDb> logger, IServerApplicationPaths paths, JellyfinDbProvider provider)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -27,19 +35,35 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
_paths = paths;
|
_paths = paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public Guid Id => Guid.Parse("3793eb59-bc8c-456c-8b9f-bd5a62a42978");
|
public Guid Id => Guid.Parse("3793eb59-bc8c-456c-8b9f-bd5a62a42978");
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public string Name => "MigrateActivityLogDatabase";
|
public string Name => "MigrateActivityLogDatabase";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
var logLevelDictionary = new Dictionary<string, LogLevel>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "None", LogLevel.None },
|
||||||
|
{ "Trace", LogLevel.Trace },
|
||||||
|
{ "Debug", LogLevel.Debug },
|
||||||
|
{ "Information", LogLevel.Information },
|
||||||
|
{ "Info", LogLevel.Information },
|
||||||
|
{ "Warn", LogLevel.Warning },
|
||||||
|
{ "Warning", LogLevel.Warning },
|
||||||
|
{ "Error", LogLevel.Error },
|
||||||
|
{ "Critical", LogLevel.Critical }
|
||||||
|
};
|
||||||
|
|
||||||
var dataPath = _paths.DataPath;
|
var dataPath = _paths.DataPath;
|
||||||
using (var connection = SQLite3.Open(
|
using (var connection = SQLite3.Open(
|
||||||
Path.Combine(dataPath, DbFilename),
|
Path.Combine(dataPath, DbFilename),
|
||||||
ConnectionFlags.ReadOnly,
|
ConnectionFlags.ReadOnly,
|
||||||
null))
|
null))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Migrating the database may take a while, do not stop Jellyfin.");
|
_logger.LogWarning("Migrating the activity database may take a while, do not stop Jellyfin.");
|
||||||
using var dbContext = _provider.CreateContext();
|
using var dbContext = _provider.CreateContext();
|
||||||
|
|
||||||
var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id ASC");
|
var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id ASC");
|
||||||
@ -56,9 +80,11 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
var newEntry = new ActivityLog(
|
var newEntry = new ActivityLog(
|
||||||
entry[1].ToString(),
|
entry[1].ToString(),
|
||||||
entry[4].ToString(),
|
entry[4].ToString(),
|
||||||
entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString()),
|
entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString()))
|
||||||
entry[7].ReadDateTime(),
|
{
|
||||||
ParseLogLevel(entry[8].ToString()));
|
DateCreated = entry[7].ReadDateTime(),
|
||||||
|
LogSeverity = logLevelDictionary[entry[8].ToString()]
|
||||||
|
};
|
||||||
|
|
||||||
if (entry[2].SQLiteType != SQLiteType.Null)
|
if (entry[2].SQLiteType != SQLiteType.Null)
|
||||||
{
|
{
|
||||||
@ -75,6 +101,8 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
newEntry.ItemId = entry[5].ToString();
|
newEntry.ItemId = entry[5].ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since code references the Id of the entries, this needs to be inserted in order.
|
||||||
|
// In order to do that, this is needed because EF Core doesn't provide a way to guarantee ordering for bulk inserts.
|
||||||
dbContext.ActivityLogs.Add(newEntry);
|
dbContext.ActivityLogs.Add(newEntry);
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
@ -89,32 +117,5 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
_logger.LogError(e, "Error renaming legacy activity log database to 'activitylog.db.old'");
|
_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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
@ -116,11 +115,6 @@ namespace MediaBrowser.Api.Devices
|
|||||||
return _deviceManager.GetDeviceOptions(request.Id);
|
return _deviceManager.GetDeviceOptions(request.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Get(GetCameraUploads request)
|
|
||||||
{
|
|
||||||
return ToOptimizedResult(_deviceManager.GetCameraUploadHistory(request.DeviceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(DeleteDevice request)
|
public void Delete(DeleteDevice request)
|
||||||
{
|
{
|
||||||
var sessions = _authRepo.Get(new AuthenticationInfoQuery
|
var sessions = _authRepo.Get(new AuthenticationInfoQuery
|
||||||
@ -134,35 +128,5 @@ namespace MediaBrowser.Api.Devices
|
|||||||
_sessionManager.Logout(session);
|
_sessionManager.Logout(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Post(PostCameraUpload request)
|
|
||||||
{
|
|
||||||
var deviceId = Request.QueryString["DeviceId"];
|
|
||||||
var album = Request.QueryString["Album"];
|
|
||||||
var id = Request.QueryString["Id"];
|
|
||||||
var name = Request.QueryString["Name"];
|
|
||||||
var req = Request.Response.HttpContext.Request;
|
|
||||||
|
|
||||||
if (req.HasFormContentType)
|
|
||||||
{
|
|
||||||
var file = req.Form.Files.Count == 0 ? null : req.Form.Files[0];
|
|
||||||
|
|
||||||
return _deviceManager.AcceptCameraUpload(deviceId, file.OpenReadStream(), new LocalFileInfo
|
|
||||||
{
|
|
||||||
MimeType = file.ContentType,
|
|
||||||
Album = album,
|
|
||||||
Name = name,
|
|
||||||
Id = id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
|
|
||||||
{
|
|
||||||
MimeType = Request.ContentType,
|
|
||||||
Album = album,
|
|
||||||
Name = name,
|
|
||||||
Id = id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -762,9 +762,7 @@ namespace MediaBrowser.Api.Library
|
|||||||
_activityManager.Create(new Jellyfin.Data.Entities.ActivityLog(
|
_activityManager.Create(new Jellyfin.Data.Entities.ActivityLog(
|
||||||
string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
|
string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
|
||||||
"UserDownloadingContent",
|
"UserDownloadingContent",
|
||||||
auth.UserId,
|
auth.UserId)
|
||||||
DateTime.UtcNow,
|
|
||||||
LogLevel.Trace)
|
|
||||||
{
|
{
|
||||||
ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device),
|
ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device),
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Activity;
|
using MediaBrowser.Model.Activity;
|
||||||
@ -49,10 +47,6 @@ namespace MediaBrowser.Api.System
|
|||||||
|
|
||||||
public object Get(GetActivityLogs request)
|
public object Get(GetActivityLogs request)
|
||||||
{
|
{
|
||||||
DateTime? minDate = string.IsNullOrWhiteSpace(request.MinDate) ?
|
|
||||||
(DateTime?)null :
|
|
||||||
DateTime.Parse(request.MinDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
|
|
||||||
|
|
||||||
var result = _activityManager.GetPagedResult(request.StartIndex, request.Limit);
|
var result = _activityManager.GetPagedResult(request.StartIndex, request.Limit);
|
||||||
|
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
|
@ -11,11 +11,6 @@ namespace MediaBrowser.Controller.Devices
|
|||||||
{
|
{
|
||||||
public interface IDeviceManager
|
public interface IDeviceManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Occurs when [camera image uploaded].
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the capabilities.
|
/// Saves the capabilities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -45,22 +40,6 @@ namespace MediaBrowser.Controller.Devices
|
|||||||
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
||||||
QueryResult<DeviceInfo> GetDevices(DeviceQuery query);
|
QueryResult<DeviceInfo> GetDevices(DeviceQuery query);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the upload history.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
|
||||||
/// <returns>ContentUploadHistory.</returns>
|
|
||||||
ContentUploadHistory GetCameraUploadHistory(string deviceId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Accepts the upload.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
|
||||||
/// <param name="stream">The stream.</param>
|
|
||||||
/// <param name="file">The file.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this instance [can access device] the specified user identifier.
|
/// Determines whether this instance [can access device] the specified user identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 16.0.30011.22
|
VisualStudioVersion = 15.0.26730.3
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server", "Jellyfin.Server\Jellyfin.Server.csproj", "{07E39F42-A2C6-4B32-AF8C-725F957A73FF}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Server", "Jellyfin.Server\Jellyfin.Server.csproj", "{07E39F42-A2C6-4B32-AF8C-725F957A73FF}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Loading…
x
Reference in New Issue
Block a user