Add Api and startup check for sufficient storage capacity (#13888)

This commit is contained in:
JPVenson 2025-04-21 05:06:50 +03:00 committed by GitHub
parent 5e4bd744c0
commit a0931baa8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 560 additions and 125 deletions

View file

@ -1,9 +1,12 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Server.Implementations.StorageHelpers;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.System;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
@ -19,6 +22,7 @@ public class SystemManager : ISystemManager
private readonly IServerConfigurationManager _configurationManager;
private readonly IStartupOptions _startupOptions;
private readonly IInstallationManager _installationManager;
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="SystemManager"/> class.
@ -29,13 +33,15 @@ public class SystemManager : ISystemManager
/// <param name="configurationManager">Instance of <see cref="IServerConfigurationManager"/>.</param>
/// <param name="startupOptions">Instance of <see cref="IStartupOptions"/>.</param>
/// <param name="installationManager">Instance of <see cref="IInstallationManager"/>.</param>
/// <param name="libraryManager">Instance of <see cref="ILibraryManager"/>.</param>
public SystemManager(
IHostApplicationLifetime applicationLifetime,
IServerApplicationHost applicationHost,
IServerApplicationPaths applicationPaths,
IServerConfigurationManager configurationManager,
IStartupOptions startupOptions,
IInstallationManager installationManager)
IInstallationManager installationManager,
ILibraryManager libraryManager)
{
_applicationLifetime = applicationLifetime;
_applicationHost = applicationHost;
@ -43,6 +49,7 @@ public class SystemManager : ISystemManager
_configurationManager = configurationManager;
_startupOptions = startupOptions;
_installationManager = installationManager;
_libraryManager = libraryManager;
}
/// <inheritdoc />
@ -57,6 +64,7 @@ public class SystemManager : ISystemManager
WebSocketPortNumber = _applicationHost.HttpPort,
CompletedInstallations = _installationManager.CompletedInstallations.ToArray(),
Id = _applicationHost.SystemId,
#pragma warning disable CS0618 // Type or member is obsolete
ProgramDataPath = _applicationPaths.ProgramDataPath,
WebPath = _applicationPaths.WebPath,
LogPath = _applicationPaths.LogDirectoryPath,
@ -64,6 +72,7 @@ public class SystemManager : ISystemManager
InternalMetadataPath = _applicationPaths.InternalMetadataPath,
CachePath = _applicationPaths.CachePath,
TranscodingTempPath = _configurationManager.GetTranscodePath(),
#pragma warning restore CS0618 // Type or member is obsolete
ServerName = _applicationHost.FriendlyName,
LocalAddress = _applicationHost.GetSmartApiUrl(request),
StartupWizardCompleted = _configurationManager.CommonConfiguration.IsStartupWizardCompleted,
@ -73,6 +82,29 @@ public class SystemManager : ISystemManager
};
}
/// <inheritdoc/>
public SystemStorageInfo GetSystemStorageInfo()
{
var virtualFolderInfos = _libraryManager.GetVirtualFolders().Select(e => new LibraryStorageInfo()
{
Id = Guid.Parse(e.ItemId),
Name = e.Name,
Folders = e.Locations.Select(f => StorageHelper.GetFreeSpaceOf(f)).ToArray()
});
return new SystemStorageInfo()
{
ProgramDataFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.ProgramDataPath),
WebFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.WebPath),
LogFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.LogDirectoryPath),
ImageCacheFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.ImageCachePath),
InternalMetadataFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.InternalMetadataPath),
CacheFolder = StorageHelper.GetFreeSpaceOf(_applicationPaths.CachePath),
TranscodingTempFolder = StorageHelper.GetFreeSpaceOf(_configurationManager.GetTranscodePath()),
Libraries = virtualFolderInfos.ToArray()
};
}
/// <inheritdoc />
public PublicSystemInfo GetPublicSystemInfo(HttpRequest request)
{

View file

@ -6,6 +6,7 @@ using System.Linq;
using System.Net.Mime;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Models.SystemInfoDtos;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
@ -71,6 +72,19 @@ public class SystemController : BaseJellyfinApiController
public ActionResult<SystemInfo> GetSystemInfo()
=> _systemManager.GetSystemInfo(Request);
/// <summary>
/// Gets information about the server.
/// </summary>
/// <response code="200">Information retrieved.</response>
/// <response code="403">User does not have permission to retrieve information.</response>
/// <returns>A <see cref="SystemInfo"/> with info about the system.</returns>
[HttpGet("Info/Storage")]
[Authorize(Policy = Policies.RequiresElevation)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public ActionResult<SystemStorageDto> GetSystemStorage()
=> Ok(SystemStorageDto.FromSystemStorageInfo(_systemManager.GetSystemStorageInfo()));
/// <summary>
/// Gets public information about the server.
/// </summary>

View file

@ -0,0 +1,46 @@
using MediaBrowser.Model.System;
namespace Jellyfin.Api.Models.SystemInfoDtos;
/// <summary>
/// Contains information about a specific folder.
/// </summary>
public record FolderStorageDto
{
/// <summary>
/// Gets the path of the folder in question.
/// </summary>
public required string Path { get; init; }
/// <summary>
/// Gets the free space of the underlying storage device of the <see cref="Path"/>.
/// </summary>
public long FreeSpace { get; init; }
/// <summary>
/// Gets the used space of the underlying storage device of the <see cref="Path"/>.
/// </summary>
public long UsedSpace { get; init; }
/// <summary>
/// Gets the kind of storage device of the <see cref="Path"/>.
/// </summary>
public string? StorageType { get; init; }
/// <summary>
/// Gets the Device Identifier.
/// </summary>
public string? DeviceId { get; init; }
internal static FolderStorageDto FromFolderStorageInfo(FolderStorageInfo model)
{
return new()
{
Path = model.Path,
FreeSpace = model.FreeSpace,
UsedSpace = model.UsedSpace,
StorageType = model.StorageType,
DeviceId = model.DeviceId
};
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.System;
namespace Jellyfin.Api.Models.SystemInfoDtos;
/// <summary>
/// Contains informations about a libraries storage informations.
/// </summary>
public record LibraryStorageDto
{
/// <summary>
/// Gets or sets the Library Id.
/// </summary>
public required Guid Id { get; set; }
/// <summary>
/// Gets or sets the name of the library.
/// </summary>
public required string Name { get; set; }
/// <summary>
/// Gets or sets the storage informations about the folders used in a library.
/// </summary>
public required IReadOnlyCollection<FolderStorageDto> Folders { get; set; }
internal static LibraryStorageDto FromLibraryStorageModel(LibraryStorageInfo model)
{
return new()
{
Id = model.Id,
Name = model.Name,
Folders = model.Folders.Select(FolderStorageDto.FromFolderStorageInfo).ToArray()
};
}
}

View file

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.System;
namespace Jellyfin.Api.Models.SystemInfoDtos;
/// <summary>
/// Contains informations about the systems storage.
/// </summary>
public record SystemStorageDto
{
/// <summary>
/// Gets or sets the Storage information of the program data folder.
/// </summary>
public required FolderStorageDto ProgramDataFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the web UI resources folder.
/// </summary>
public required FolderStorageDto WebFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the folder where images are cached.
/// </summary>
public required FolderStorageDto ImageCacheFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the cache folder.
/// </summary>
public required FolderStorageDto CacheFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the folder where logfiles are saved to.
/// </summary>
public required FolderStorageDto LogFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the folder where metadata is stored.
/// </summary>
public required FolderStorageDto InternalMetadataFolder { get; set; }
/// <summary>
/// Gets or sets the Storage information of the transcoding cache.
/// </summary>
public required FolderStorageDto TranscodingTempFolder { get; set; }
/// <summary>
/// Gets or sets the storage informations of all libraries.
/// </summary>
public required IReadOnlyCollection<LibraryStorageDto> Libraries { get; set; }
internal static SystemStorageDto FromSystemStorageInfo(SystemStorageInfo model)
{
return new SystemStorageDto()
{
ProgramDataFolder = FolderStorageDto.FromFolderStorageInfo(model.ProgramDataFolder),
WebFolder = FolderStorageDto.FromFolderStorageInfo(model.WebFolder),
ImageCacheFolder = FolderStorageDto.FromFolderStorageInfo(model.ImageCacheFolder),
CacheFolder = FolderStorageDto.FromFolderStorageInfo(model.CacheFolder),
LogFolder = FolderStorageDto.FromFolderStorageInfo(model.LogFolder),
InternalMetadataFolder = FolderStorageDto.FromFolderStorageInfo(model.InternalMetadataFolder),
TranscodingTempFolder = FolderStorageDto.FromFolderStorageInfo(model.TranscodingTempFolder),
Libraries = model.Libraries.Select(LibraryStorageDto.FromLibraryStorageModel).ToArray()
};
}
}

View file

@ -0,0 +1,109 @@
using System;
using System.Globalization;
using System.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Implementations.StorageHelpers;
/// <summary>
/// Contains methods to help with checking for storage and returning storage data for jellyfin folders.
/// </summary>
public static class StorageHelper
{
private const long TwoGigabyte = 2_147_483_647L;
private const long FiveHundredAndTwelveMegaByte = 536_870_911L;
private static readonly string[] _byteHumanizedSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
/// <summary>
/// Tests the available storage capacity on the jellyfin paths with estimated minimum values.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logger">Logger.</param>
public static void TestCommonPathsForStorageCapacity(IApplicationPaths applicationPaths, ILogger logger)
{
TestDataDirectorySize(applicationPaths.DataPath, logger, TwoGigabyte);
TestDataDirectorySize(applicationPaths.LogDirectoryPath, logger, FiveHundredAndTwelveMegaByte);
TestDataDirectorySize(applicationPaths.CachePath, logger, TwoGigabyte);
TestDataDirectorySize(applicationPaths.ProgramDataPath, logger, TwoGigabyte);
TestDataDirectorySize(applicationPaths.TempDirectory, logger, TwoGigabyte);
}
/// <summary>
/// Gets the free space of a specific directory.
/// </summary>
/// <param name="path">Path to a folder.</param>
/// <returns>The number of bytes available space.</returns>
public static FolderStorageInfo GetFreeSpaceOf(string path)
{
try
{
var driveInfo = new DriveInfo(path);
return new FolderStorageInfo()
{
Path = path,
FreeSpace = driveInfo.AvailableFreeSpace,
UsedSpace = driveInfo.TotalSize - driveInfo.AvailableFreeSpace,
StorageType = driveInfo.DriveType.ToString(),
DeviceId = driveInfo.Name,
};
}
catch
{
return new FolderStorageInfo()
{
Path = path,
FreeSpace = -1,
UsedSpace = -1,
StorageType = null,
DeviceId = null
};
}
}
/// <summary>
/// Gets the underlying drive data from a given path and checks if the available storage capacity matches the threshold.
/// </summary>
/// <param name="path">The path to a folder to evaluate.</param>
/// <param name="logger">The logger.</param>
/// <param name="threshold">The threshold to check for or -1 to just log the data.</param>
/// <exception cref="InvalidOperationException">Thrown when the threshold is not available on the underlying storage.</exception>
private static void TestDataDirectorySize(string path, ILogger logger, long threshold = -1)
{
logger.LogDebug("Check path {TestPath} for storage capacity", path);
var drive = new DriveInfo(path);
if (threshold != -1 && drive.AvailableFreeSpace < threshold)
{
throw new InvalidOperationException($"The path `{path}` has insufficient free space. Required: at least {HumanizeStorageSize(threshold)}.");
}
logger.LogInformation(
"Storage path `{TestPath}` ({StorageType}) successfully checked with {FreeSpace} free which is over the minimum of {MinFree}.",
path,
drive.DriveType,
HumanizeStorageSize(drive.AvailableFreeSpace),
HumanizeStorageSize(threshold));
}
/// <summary>
/// Formats a size in bytes into a common human readable form.
/// </summary>
/// <remarks>
/// Taken and slightly modified from https://stackoverflow.com/a/4975942/1786007 .
/// </remarks>
/// <param name="byteCount">The size in bytes.</param>
/// <returns>A human readable approximate representation of the argument.</returns>
public static string HumanizeStorageSize(long byteCount)
{
if (byteCount == 0)
{
return $"0{_byteHumanizedSuffixes[0]}";
}
var bytes = Math.Abs(byteCount);
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
var num = Math.Round(bytes / Math.Pow(1024, place), 1);
return (Math.Sign(byteCount) * num).ToString(CultureInfo.InvariantCulture) + _byteHumanizedSuffixes[place];
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@ -11,6 +12,7 @@ using Emby.Server.Implementations;
using Jellyfin.Database.Implementations;
using Jellyfin.Server.Extensions;
using Jellyfin.Server.Helpers;
using Jellyfin.Server.Implementations.StorageHelpers;
using Jellyfin.Server.ServerSetupApp;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
@ -120,6 +122,8 @@ namespace Jellyfin.Server
}
}
StorageHelper.TestCommonPathsForStorageCapacity(appPaths, _loggerFactory.CreateLogger<Startup>());
StartupHelpers.PerformStaticInitialization();
await Migrations.MigrationRunner.RunPreStartup(appPaths, _loggerFactory).ConfigureAwait(false);

View file

@ -1,5 +1,6 @@
using MediaBrowser.Model.System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace MediaBrowser.Controller;
@ -31,4 +32,10 @@ public interface ISystemManager
/// Starts the application shutdown process.
/// </summary>
void Shutdown();
/// <summary>
/// Gets the systems storage resources.
/// </summary>
/// <returns>The <see cref="SystemStorageInfo"/>.</returns>
SystemStorageInfo GetSystemStorageInfo();
}

View file

@ -0,0 +1,32 @@
namespace MediaBrowser.Model.System;
/// <summary>
/// Contains information about a specific folder.
/// </summary>
public record FolderStorageInfo
{
/// <summary>
/// Gets the path of the folder in question.
/// </summary>
public required string Path { get; init; }
/// <summary>
/// Gets the free space of the underlying storage device of the <see cref="Path"/>.
/// </summary>
public long FreeSpace { get; init; }
/// <summary>
/// Gets the used space of the underlying storage device of the <see cref="Path"/>.
/// </summary>
public long UsedSpace { get; init; }
/// <summary>
/// Gets the kind of storage device of the <see cref="Path"/>.
/// </summary>
public string? StorageType { get; init; }
/// <summary>
/// Gets the Device Identifier.
/// </summary>
public string? DeviceId { get; init; }
}

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
namespace MediaBrowser.Model.System;
/// <summary>
/// Contains informations about a libraries storage informations.
/// </summary>
public class LibraryStorageInfo
{
/// <summary>
/// Gets or sets the Library Id.
/// </summary>
public required Guid Id { get; set; }
/// <summary>
/// Gets or sets the name of the library.
/// </summary>
public required string Name { get; set; }
/// <summary>
/// Gets or sets the storage informations about the folders used in a library.
/// </summary>
public required IReadOnlyCollection<FolderStorageInfo> Folders { get; set; }
}

View file

@ -6,133 +6,139 @@ using System.Collections.Generic;
using System.ComponentModel;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Model.System
namespace MediaBrowser.Model.System;
/// <summary>
/// Class SystemInfo.
/// </summary>
public class SystemInfo : PublicSystemInfo
{
/// <summary>
/// Class SystemInfo.
/// Initializes a new instance of the <see cref="SystemInfo" /> class.
/// </summary>
public class SystemInfo : PublicSystemInfo
public SystemInfo()
{
/// <summary>
/// Initializes a new instance of the <see cref="SystemInfo" /> class.
/// </summary>
public SystemInfo()
{
CompletedInstallations = Array.Empty<InstallationInfo>();
}
/// <summary>
/// Gets or sets the display name of the operating system.
/// </summary>
/// <value>The display name of the operating system.</value>
[Obsolete("This is no longer set")]
public string OperatingSystemDisplayName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the package name.
/// </summary>
/// <value>The value of the '-package' command line argument.</value>
public string PackageName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has pending restart.
/// </summary>
/// <value><c>true</c> if this instance has pending restart; otherwise, <c>false</c>.</value>
public bool HasPendingRestart { get; set; }
public bool IsShuttingDown { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [supports library monitor].
/// </summary>
/// <value><c>true</c> if [supports library monitor]; otherwise, <c>false</c>.</value>
public bool SupportsLibraryMonitor { get; set; }
/// <summary>
/// Gets or sets the web socket port number.
/// </summary>
/// <value>The web socket port number.</value>
public int WebSocketPortNumber { get; set; }
/// <summary>
/// Gets or sets the completed installations.
/// </summary>
/// <value>The completed installations.</value>
public InstallationInfo[] CompletedInstallations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance can self restart.
/// </summary>
/// <value><c>true</c>.</value>
[Obsolete("This is always true")]
[DefaultValue(true)]
public bool CanSelfRestart { get; set; } = true;
[Obsolete("This is always false")]
[DefaultValue(false)]
public bool CanLaunchWebBrowser { get; set; } = false;
/// <summary>
/// Gets or sets the program data path.
/// </summary>
/// <value>The program data path.</value>
public string ProgramDataPath { get; set; }
/// <summary>
/// Gets or sets the web UI resources path.
/// </summary>
/// <value>The web UI resources path.</value>
public string WebPath { get; set; }
/// <summary>
/// Gets or sets the items by name path.
/// </summary>
/// <value>The items by name path.</value>
public string ItemsByNamePath { get; set; }
/// <summary>
/// Gets or sets the cache path.
/// </summary>
/// <value>The cache path.</value>
public string CachePath { get; set; }
/// <summary>
/// Gets or sets the log path.
/// </summary>
/// <value>The log path.</value>
public string LogPath { get; set; }
/// <summary>
/// Gets or sets the internal metadata path.
/// </summary>
/// <value>The internal metadata path.</value>
public string InternalMetadataPath { get; set; }
/// <summary>
/// Gets or sets the transcode path.
/// </summary>
/// <value>The transcode path.</value>
public string TranscodingTempPath { get; set; }
/// <summary>
/// Gets or sets the list of cast receiver applications.
/// </summary>
public IReadOnlyList<CastReceiverApplication> CastReceiverApplications { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has update available.
/// </summary>
/// <value><c>true</c> if this instance has update available; otherwise, <c>false</c>.</value>
[Obsolete("This should be handled by the package manager")]
[DefaultValue(false)]
public bool HasUpdateAvailable { get; set; }
[Obsolete("This isn't set correctly anymore")]
[DefaultValue("System")]
public string EncoderLocation { get; set; } = "System";
[Obsolete("This is no longer set")]
[DefaultValue("X64")]
public string SystemArchitecture { get; set; } = "X64";
CompletedInstallations = Array.Empty<InstallationInfo>();
}
/// <summary>
/// Gets or sets the display name of the operating system.
/// </summary>
/// <value>The display name of the operating system.</value>
[Obsolete("This is no longer set")]
public string OperatingSystemDisplayName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the package name.
/// </summary>
/// <value>The value of the '-package' command line argument.</value>
public string PackageName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has pending restart.
/// </summary>
/// <value><c>true</c> if this instance has pending restart; otherwise, <c>false</c>.</value>
public bool HasPendingRestart { get; set; }
public bool IsShuttingDown { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [supports library monitor].
/// </summary>
/// <value><c>true</c> if [supports library monitor]; otherwise, <c>false</c>.</value>
public bool SupportsLibraryMonitor { get; set; }
/// <summary>
/// Gets or sets the web socket port number.
/// </summary>
/// <value>The web socket port number.</value>
public int WebSocketPortNumber { get; set; }
/// <summary>
/// Gets or sets the completed installations.
/// </summary>
/// <value>The completed installations.</value>
public InstallationInfo[] CompletedInstallations { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance can self restart.
/// </summary>
/// <value><c>true</c>.</value>
[Obsolete("This is always true")]
[DefaultValue(true)]
public bool CanSelfRestart { get; set; } = true;
[Obsolete("This is always false")]
[DefaultValue(false)]
public bool CanLaunchWebBrowser { get; set; } = false;
/// <summary>
/// Gets or sets the program data path.
/// </summary>
/// <value>The program data path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string ProgramDataPath { get; set; }
/// <summary>
/// Gets or sets the web UI resources path.
/// </summary>
/// <value>The web UI resources path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string WebPath { get; set; }
/// <summary>
/// Gets or sets the items by name path.
/// </summary>
/// <value>The items by name path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string ItemsByNamePath { get; set; }
/// <summary>
/// Gets or sets the cache path.
/// </summary>
/// <value>The cache path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string CachePath { get; set; }
/// <summary>
/// Gets or sets the log path.
/// </summary>
/// <value>The log path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string LogPath { get; set; }
/// <summary>
/// Gets or sets the internal metadata path.
/// </summary>
/// <value>The internal metadata path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string InternalMetadataPath { get; set; }
/// <summary>
/// Gets or sets the transcode path.
/// </summary>
/// <value>The transcode path.</value>
[Obsolete("Use the newer SystemStorageDto instead")]
public string TranscodingTempPath { get; set; }
/// <summary>
/// Gets or sets the list of cast receiver applications.
/// </summary>
public IReadOnlyList<CastReceiverApplication> CastReceiverApplications { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has update available.
/// </summary>
/// <value><c>true</c> if this instance has update available; otherwise, <c>false</c>.</value>
[Obsolete("This should be handled by the package manager")]
[DefaultValue(false)]
public bool HasUpdateAvailable { get; set; }
[Obsolete("This isn't set correctly anymore")]
[DefaultValue("System")]
public string EncoderLocation { get; set; } = "System";
[Obsolete("This is no longer set")]
[DefaultValue("X64")]
public string SystemArchitecture { get; set; } = "X64";
}

View file

@ -0,0 +1,56 @@
using System.Collections.Generic;
namespace MediaBrowser.Model.System;
/// <summary>
/// Contains informations about the systems storage.
/// </summary>
public class SystemStorageInfo
{
/// <summary>
/// Gets or sets the program data path.
/// </summary>
/// <value>The program data path.</value>
public required FolderStorageInfo ProgramDataFolder { get; set; }
/// <summary>
/// Gets or sets the web UI resources path.
/// </summary>
/// <value>The web UI resources path.</value>
public required FolderStorageInfo WebFolder { get; set; }
/// <summary>
/// Gets or sets the items by name path.
/// </summary>
/// <value>The items by name path.</value>
public required FolderStorageInfo ImageCacheFolder { get; set; }
/// <summary>
/// Gets or sets the cache path.
/// </summary>
/// <value>The cache path.</value>
public required FolderStorageInfo CacheFolder { get; set; }
/// <summary>
/// Gets or sets the log path.
/// </summary>
/// <value>The log path.</value>
public required FolderStorageInfo LogFolder { get; set; }
/// <summary>
/// Gets or sets the internal metadata path.
/// </summary>
/// <value>The internal metadata path.</value>
public required FolderStorageInfo InternalMetadataFolder { get; set; }
/// <summary>
/// Gets or sets the transcode path.
/// </summary>
/// <value>The transcode path.</value>
public required FolderStorageInfo TranscodingTempFolder { get; set; }
/// <summary>
/// Gets or sets the storage informations of all libraries.
/// </summary>
public required IReadOnlyCollection<LibraryStorageInfo> Libraries { get; set; }
}