mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-13 19:20:23 +01:00
update to current master to resolve merge conflict
This commit is contained in:
@@ -10,8 +10,6 @@ namespace Emby.Server.Implementations.AppBase
|
||||
/// </summary>
|
||||
public abstract class BaseApplicationPaths : IApplicationPaths
|
||||
{
|
||||
private string _dataPath;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
|
||||
/// </summary>
|
||||
@@ -33,7 +31,7 @@ namespace Emby.Server.Implementations.AppBase
|
||||
CachePath = cacheDirectoryPath;
|
||||
WebPath = webDirectoryPath;
|
||||
|
||||
_dataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName;
|
||||
DataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,7 +53,7 @@ namespace Emby.Server.Implementations.AppBase
|
||||
/// Gets the folder path to the data directory.
|
||||
/// </summary>
|
||||
/// <value>The data directory.</value>
|
||||
public string DataPath => _dataPath;
|
||||
public string DataPath { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string VirtualDataPath => "%AppDataPath%";
|
||||
|
||||
@@ -13,9 +13,7 @@ using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna;
|
||||
using Emby.Dlna.Main;
|
||||
using Emby.Dlna.Ssdp;
|
||||
using Emby.Naming.Common;
|
||||
using Emby.Photos;
|
||||
using Emby.Server.Implementations.Channels;
|
||||
@@ -58,7 +56,6 @@ using MediaBrowser.Controller.Chapters;
|
||||
using MediaBrowser.Controller.ClientEvent;
|
||||
using MediaBrowser.Controller.Collections;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@@ -82,7 +79,6 @@ using MediaBrowser.LocalMetadata.Savers;
|
||||
using MediaBrowser.MediaEncoding.BdInfo;
|
||||
using MediaBrowser.MediaEncoding.Subtitles;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
@@ -101,7 +97,6 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Prometheus.DotNetRuntime;
|
||||
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||
@@ -133,7 +128,7 @@ namespace Emby.Server.Implementations
|
||||
/// <value>All concrete types.</value>
|
||||
private Type[] _allConcreteTypes;
|
||||
|
||||
private bool _disposed = false;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
|
||||
@@ -184,26 +179,16 @@ namespace Emby.Server.Implementations
|
||||
|
||||
public bool CoreStartupHasCompleted { get; private set; }
|
||||
|
||||
public virtual bool CanLaunchWebBrowser => Environment.UserInteractive
|
||||
&& !_startupOptions.IsService
|
||||
&& (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="INetworkManager"/> singleton instance.
|
||||
/// </summary>
|
||||
public INetworkManager NetManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance has changes that require the entire application to restart.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
|
||||
/// <inheritdoc />
|
||||
public bool HasPendingRestart { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsShuttingDown { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ShouldRestart { get; private set; }
|
||||
public bool ShouldRestart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
@@ -461,7 +446,7 @@ namespace Emby.Server.Implementations
|
||||
|
||||
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
|
||||
|
||||
NetManager = new NetworkManager(ConfigurationManager, LoggerFactory.CreateLogger<NetworkManager>());
|
||||
NetManager = new NetworkManager(ConfigurationManager, _startupConfig, LoggerFactory.CreateLogger<NetworkManager>());
|
||||
|
||||
// Initialize runtime stat collection
|
||||
if (ConfigurationManager.Configuration.EnableMetrics)
|
||||
@@ -507,6 +492,8 @@ namespace Emby.Server.Implementations
|
||||
serviceCollection.AddSingleton<IFileSystem, ManagedFileSystem>();
|
||||
serviceCollection.AddSingleton<IShortcutHandler, MbLinkShortcutHandler>();
|
||||
|
||||
serviceCollection.AddScoped<ISystemManager, SystemManager>();
|
||||
|
||||
serviceCollection.AddSingleton<TmdbClientManager>();
|
||||
|
||||
serviceCollection.AddSingleton(NetManager);
|
||||
@@ -572,8 +559,6 @@ namespace Emby.Server.Implementations
|
||||
|
||||
serviceCollection.AddSingleton<ISessionManager, SessionManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDlnaManager, DlnaManager>();
|
||||
|
||||
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
|
||||
@@ -585,8 +570,6 @@ namespace Emby.Server.Implementations
|
||||
|
||||
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
|
||||
|
||||
serviceCollection.AddSingleton<IChapterManager, ChapterManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
|
||||
@@ -850,24 +833,6 @@ namespace Emby.Server.Implementations
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Restart()
|
||||
{
|
||||
ShouldRestart = true;
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Shutdown()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
IsShuttingDown = true;
|
||||
Resolve<IHostApplicationLifetime>().StopApplication();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the composable part assemblies.
|
||||
/// </summary>
|
||||
@@ -923,49 +888,6 @@ namespace Emby.Server.Implementations
|
||||
|
||||
protected abstract IEnumerable<Assembly> GetAssembliesWithPartsInternal();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system status.
|
||||
/// </summary>
|
||||
/// <param name="request">Where this request originated.</param>
|
||||
/// <returns>SystemInfo.</returns>
|
||||
public SystemInfo GetSystemInfo(HttpRequest request)
|
||||
{
|
||||
return new SystemInfo
|
||||
{
|
||||
HasPendingRestart = HasPendingRestart,
|
||||
IsShuttingDown = IsShuttingDown,
|
||||
Version = ApplicationVersionString,
|
||||
WebSocketPortNumber = HttpPort,
|
||||
CompletedInstallations = Resolve<IInstallationManager>().CompletedInstallations.ToArray(),
|
||||
Id = SystemId,
|
||||
ProgramDataPath = ApplicationPaths.ProgramDataPath,
|
||||
WebPath = ApplicationPaths.WebPath,
|
||||
LogPath = ApplicationPaths.LogDirectoryPath,
|
||||
ItemsByNamePath = ApplicationPaths.InternalMetadataPath,
|
||||
InternalMetadataPath = ApplicationPaths.InternalMetadataPath,
|
||||
CachePath = ApplicationPaths.CachePath,
|
||||
CanLaunchWebBrowser = CanLaunchWebBrowser,
|
||||
TranscodingTempPath = ConfigurationManager.GetTranscodePath(),
|
||||
ServerName = FriendlyName,
|
||||
LocalAddress = GetSmartApiUrl(request),
|
||||
SupportsLibraryMonitor = true,
|
||||
PackageName = _startupOptions.PackageName
|
||||
};
|
||||
}
|
||||
|
||||
public PublicSystemInfo GetPublicSystemInfo(HttpRequest request)
|
||||
{
|
||||
return new PublicSystemInfo
|
||||
{
|
||||
Version = ApplicationVersionString,
|
||||
ProductName = ApplicationProductName,
|
||||
Id = SystemId,
|
||||
ServerName = FriendlyName,
|
||||
LocalAddress = GetSmartApiUrl(request),
|
||||
StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetSmartApiUrl(IPAddress remoteAddr)
|
||||
{
|
||||
@@ -983,7 +905,7 @@ namespace Emby.Server.Implementations
|
||||
/// <inheritdoc/>
|
||||
public string GetSmartApiUrl(HttpRequest request)
|
||||
{
|
||||
// Return the host in the HTTP request as the API url
|
||||
// Return the host in the HTTP request as the API URL if not configured otherwise
|
||||
if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest)
|
||||
{
|
||||
int? requestPort = request.Host.Port;
|
||||
@@ -1018,7 +940,7 @@ namespace Emby.Server.Implementations
|
||||
public string GetApiUrlForLocalAccess(IPAddress ipAddress = null, bool allowHttps = true)
|
||||
{
|
||||
// With an empty source, the port will be null
|
||||
var smart = NetManager.GetBindAddress(ipAddress, out _, true);
|
||||
var smart = NetManager.GetBindAddress(ipAddress, out _, false);
|
||||
var scheme = !allowHttps ? Uri.UriSchemeHttp : null;
|
||||
int? port = !allowHttps ? HttpPort : null;
|
||||
return GetLocalApiUrl(smart, scheme, port);
|
||||
|
||||
@@ -371,8 +371,11 @@ namespace Emby.Server.Implementations.Channels
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
await using FileStream createStream = File.Create(path);
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false);
|
||||
FileStream createStream = File.Create(path);
|
||||
await using (createStream.ConfigureAwait(false))
|
||||
{
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaSources, _jsonOptions).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1156,7 +1159,7 @@ namespace Emby.Server.Implementations.Channels
|
||||
|
||||
if (info.People is not null && info.People.Count > 0)
|
||||
{
|
||||
_libraryManager.UpdatePeople(item, info.People);
|
||||
await _libraryManager.UpdatePeopleAsync(item, info.People, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else if (forceUpdate)
|
||||
|
||||
@@ -3540,10 +3540,7 @@ namespace Emby.Server.Implementations.Data
|
||||
.Append(paramName)
|
||||
.Append("))) OR ");
|
||||
|
||||
if (statement is not null)
|
||||
{
|
||||
statement.TryBind(paramName, query.PersonIds[i]);
|
||||
}
|
||||
statement?.TryBind(paramName, query.PersonIds[i]);
|
||||
}
|
||||
|
||||
clauseBuilder.Length -= Or.Length;
|
||||
@@ -4382,7 +4379,7 @@ namespace Emby.Server.Implementations.Data
|
||||
|
||||
foreach (var videoType in query.VideoTypes)
|
||||
{
|
||||
videoTypes.Add("data like '%\"VideoType\":\"" + videoType.ToString() + "\"%'");
|
||||
videoTypes.Add("data like '%\"VideoType\":\"" + videoType + "\"%'");
|
||||
}
|
||||
|
||||
whereClauses.Add("(" + string.Join(" OR ", videoTypes) + ")");
|
||||
|
||||
@@ -22,6 +22,7 @@ using MediaBrowser.Controller.Lyrics;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Playlists;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Trickplay;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
@@ -52,6 +53,7 @@ namespace Emby.Server.Implementations.Dto
|
||||
private readonly Lazy<ILiveTvManager> _livetvManagerFactory;
|
||||
|
||||
private readonly ILyricManager _lyricManager;
|
||||
private readonly ITrickplayManager _trickplayManager;
|
||||
|
||||
public DtoService(
|
||||
ILogger<DtoService> logger,
|
||||
@@ -63,7 +65,8 @@ namespace Emby.Server.Implementations.Dto
|
||||
IApplicationHost appHost,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
Lazy<ILiveTvManager> livetvManagerFactory,
|
||||
ILyricManager lyricManager)
|
||||
ILyricManager lyricManager,
|
||||
ITrickplayManager trickplayManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
@@ -75,6 +78,7 @@ namespace Emby.Server.Implementations.Dto
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_livetvManagerFactory = livetvManagerFactory;
|
||||
_lyricManager = lyricManager;
|
||||
_trickplayManager = trickplayManager;
|
||||
}
|
||||
|
||||
private ILiveTvManager LivetvManager => _livetvManagerFactory.Value;
|
||||
@@ -1059,6 +1063,11 @@ namespace Emby.Server.Implementations.Dto
|
||||
dto.Chapters = _itemRepo.GetChapters(item);
|
||||
}
|
||||
|
||||
if (options.ContainsField(ItemFields.Trickplay))
|
||||
{
|
||||
dto.Trickplay = _trickplayManager.GetTrickplayManifest(item).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (video.ExtraType.HasValue)
|
||||
{
|
||||
dto.ExtraType = video.ExtraType.Value.ToString();
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
|
||||
<NoWarn>AD0001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
|
||||
@@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging;
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Class UdpServerEntryPoint.
|
||||
/// Class responsible for registering all UDP broadcast endpoints and their handlers.
|
||||
/// </summary>
|
||||
public sealed class UdpServerEntryPoint : IServerEntryPoint
|
||||
{
|
||||
@@ -35,14 +35,13 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
private readonly IConfiguration _config;
|
||||
private readonly IConfigurationManager _configurationManager;
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly bool _enableMultiSocketBinding;
|
||||
|
||||
/// <summary>
|
||||
/// The UDP server.
|
||||
/// </summary>
|
||||
private List<UdpServer> _udpServers;
|
||||
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
private bool _disposed = false;
|
||||
private readonly List<UdpServer> _udpServers;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UdpServerEntryPoint" /> class.
|
||||
@@ -65,7 +64,6 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
_configurationManager = configurationManager;
|
||||
_networkManager = networkManager;
|
||||
_udpServers = new List<UdpServer>();
|
||||
_enableMultiSocketBinding = OperatingSystem.IsWindows() || OperatingSystem.IsLinux();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -80,14 +78,16 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
|
||||
try
|
||||
{
|
||||
if (_enableMultiSocketBinding)
|
||||
// Linux needs to bind to the broadcast addresses to get broadcast traffic
|
||||
// Windows receives broadcast fine when binding to just the interface, it is unable to bind to broadcast addresses
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
// Add global broadcast socket
|
||||
// Add global broadcast listener
|
||||
var server = new UdpServer(_logger, _appHost, _config, IPAddress.Broadcast, PortNumber);
|
||||
server.Start(_cancellationTokenSource.Token);
|
||||
_udpServers.Add(server);
|
||||
|
||||
// Add bind address specific broadcast sockets
|
||||
// Add bind address specific broadcast listeners
|
||||
// IPv6 is currently unsupported
|
||||
var validInterfaces = _networkManager.GetInternalBindAddresses().Where(i => i.AddressFamily == AddressFamily.InterNetwork);
|
||||
foreach (var intf in validInterfaces)
|
||||
@@ -102,9 +102,18 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
}
|
||||
else
|
||||
{
|
||||
var server = new UdpServer(_logger, _appHost, _config, IPAddress.Any, PortNumber);
|
||||
server.Start(_cancellationTokenSource.Token);
|
||||
_udpServers.Add(server);
|
||||
// Add bind address specific broadcast listeners
|
||||
// IPv6 is currently unsupported
|
||||
var validInterfaces = _networkManager.GetInternalBindAddresses().Where(i => i.AddressFamily == AddressFamily.InterNetwork);
|
||||
foreach (var intf in validInterfaces)
|
||||
{
|
||||
var intfAddress = intf.Address;
|
||||
_logger.LogDebug("Binding UDP server to {Address} on port {PortNumber}", intfAddress, PortNumber);
|
||||
|
||||
var server = new UdpServer(_logger, _appHost, _config, intfAddress, PortNumber);
|
||||
server.Start(_cancellationTokenSource.Token);
|
||||
_udpServers.Add(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
@@ -119,7 +128,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().Name);
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
using MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer
|
||||
|
||||
@@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.IO
|
||||
|
||||
DisposeTimer();
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.IO
|
||||
}
|
||||
|
||||
// unc path
|
||||
if (filePath.StartsWith("\\\\", StringComparison.Ordinal))
|
||||
if (filePath.StartsWith(@"\\", StringComparison.Ordinal))
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
@@ -103,15 +103,17 @@ namespace Emby.Server.Implementations.IO
|
||||
return filePath;
|
||||
}
|
||||
|
||||
var filePathSpan = filePath.AsSpan();
|
||||
|
||||
// relative path
|
||||
if (firstChar == '\\')
|
||||
{
|
||||
filePath = filePath.Substring(1);
|
||||
filePathSpan = filePathSpan.Slice(1);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Path.GetFullPath(Path.Combine(folderPath, filePath));
|
||||
return Path.GetFullPath(Path.Join(folderPath, filePathSpan));
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
||||
@@ -46,7 +46,6 @@ using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
|
||||
@@ -839,19 +838,12 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
var path = Person.GetPath(name);
|
||||
var id = GetItemByNameId<Person>(path);
|
||||
if (GetItemById(id) is not Person item)
|
||||
if (GetItemById(id) is Person item)
|
||||
{
|
||||
item = new Person
|
||||
{
|
||||
Name = name,
|
||||
Id = id,
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow,
|
||||
Path = path
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
return item;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1162,7 +1154,7 @@ namespace Emby.Server.Implementations.Library
|
||||
Name = Path.GetFileName(dir),
|
||||
|
||||
Locations = _fileSystem.GetFilePaths(dir, false)
|
||||
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
|
||||
.Where(i => Path.GetExtension(i.AsSpan()).Equals(ShortcutFileExtension, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(i =>
|
||||
{
|
||||
try
|
||||
@@ -2858,7 +2850,7 @@ namespace Emby.Server.Implementations.Library
|
||||
{
|
||||
var path = Path.Combine(virtualFolderPath, collectionType.ToString().ToLowerInvariant() + ".collection");
|
||||
|
||||
File.WriteAllBytes(path, Array.Empty<byte>());
|
||||
await File.WriteAllBytesAsync(path, Array.Empty<byte>()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
|
||||
@@ -2900,9 +2892,18 @@ namespace Emby.Server.Implementations.Library
|
||||
var saveEntity = false;
|
||||
var personEntity = GetPerson(person.Name);
|
||||
|
||||
// if PresentationUniqueKey is empty it's likely a new item.
|
||||
if (string.IsNullOrEmpty(personEntity.PresentationUniqueKey))
|
||||
if (personEntity is null)
|
||||
{
|
||||
var path = Person.GetPath(person.Name);
|
||||
personEntity = new Person()
|
||||
{
|
||||
Name = person.Name,
|
||||
Id = GetItemByNameId<Person>(path),
|
||||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow,
|
||||
Path = path
|
||||
};
|
||||
|
||||
personEntity.PresentationUniqueKey = personEntity.CreatePresentationUniqueKey();
|
||||
saveEntity = true;
|
||||
}
|
||||
@@ -3135,7 +3136,7 @@ namespace Emby.Server.Implementations.Library
|
||||
}
|
||||
|
||||
var shortcut = _fileSystem.GetFilePaths(virtualFolderPath, true)
|
||||
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
|
||||
.Where(i => Path.GetExtension(i.AsSpan()).Equals(ShortcutFileExtension, StringComparison.OrdinalIgnoreCase))
|
||||
.FirstOrDefault(f => _appHost.ExpandVirtualPath(_fileSystem.ResolveShortcut(f)).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!string.IsNullOrEmpty(shortcut))
|
||||
|
||||
@@ -48,15 +48,20 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (!string.IsNullOrEmpty(cacheKey))
|
||||
{
|
||||
FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||
try
|
||||
{
|
||||
await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// _logger.LogDebug("Found cached media info");
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error deserializing mediainfo cache");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await jsonStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +89,13 @@ namespace Emby.Server.Implementations.Library
|
||||
if (cacheFilePath is not null)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||
await using FileStream createStream = AsyncFile.OpenWrite(cacheFilePath);
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
FileStream createStream = AsyncFile.OpenWrite(cacheFilePath);
|
||||
await using (createStream.ConfigureAwait(false))
|
||||
{
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
_logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -625,17 +625,19 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (!string.IsNullOrEmpty(cacheKey))
|
||||
{
|
||||
FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||
try
|
||||
{
|
||||
await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath);
|
||||
mediaInfo = await JsonSerializer.DeserializeAsync<MediaInfo>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// _logger.LogDebug("Found cached media info");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, "_jsonSerializer.DeserializeFromFile threw an exception.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await jsonStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaInfo is null)
|
||||
@@ -664,8 +666,11 @@ namespace Emby.Server.Implementations.Library
|
||||
if (cacheFilePath is not null)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
|
||||
await using FileStream createStream = File.Create(cacheFilePath);
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
FileStream createStream = File.Create(cacheFilePath);
|
||||
await using (createStream.ConfigureAwait(false))
|
||||
{
|
||||
await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// _logger.LogDebug("Saved media info to {0}", cacheFilePath);
|
||||
}
|
||||
|
||||
@@ -94,9 +94,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
|
||||
if (AudioFileParser.IsAudioFile(args.Path, _namingOptions))
|
||||
{
|
||||
var extension = Path.GetExtension(args.Path);
|
||||
var extension = Path.GetExtension(args.Path.AsSpan());
|
||||
|
||||
if (string.Equals(extension, ".cue", StringComparison.OrdinalIgnoreCase))
|
||||
if (extension.Equals(".cue", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// if audio file exists of same name, return null
|
||||
return null;
|
||||
@@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
|
||||
if (item is not null)
|
||||
{
|
||||
item.IsShortcut = string.Equals(extension, ".strm", StringComparison.OrdinalIgnoreCase);
|
||||
item.IsShortcut = extension.Equals(".strm", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
item.IsInMixedFolder = true;
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
return false;
|
||||
}
|
||||
|
||||
return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase));
|
||||
return directoryService.GetFilePaths(fullPath).Any(i => Path.GetExtension(i.AsSpan()).Equals(".vob", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||
return GetBook(args);
|
||||
}
|
||||
|
||||
var extension = Path.GetExtension(args.Path);
|
||||
var extension = Path.GetExtension(args.Path.AsSpan());
|
||||
|
||||
if (extension is not null && _validExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
|
||||
if (_validExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// It's a book
|
||||
return new Book
|
||||
@@ -51,12 +51,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
||||
{
|
||||
var bookFiles = args.FileSystemChildren.Where(f =>
|
||||
{
|
||||
var fileExtension = Path.GetExtension(f.FullName)
|
||||
?? string.Empty;
|
||||
var fileExtension = Path.GetExtension(f.FullName.AsSpan());
|
||||
|
||||
return _validExtensions.Contains(
|
||||
fileExtension,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}).ToList();
|
||||
|
||||
// Don't return a Book if there is more (or less) than one document in the directory
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Emby.Naming.Common;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||
var resolver = new Naming.TV.EpisodeResolver(namingOptions);
|
||||
|
||||
var folderName = System.IO.Path.GetFileName(path);
|
||||
var testPath = "\\\\test\\" + folderName;
|
||||
var testPath = @"\\test\" + folderName;
|
||||
|
||||
var episodeInfo = resolver.Resolve(testPath, true);
|
||||
|
||||
|
||||
@@ -1851,7 +1851,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
return;
|
||||
}
|
||||
|
||||
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
|
||||
var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||
await using (stream.ConfigureAwait(false))
|
||||
{
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
@@ -1860,7 +1861,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
Async = true
|
||||
};
|
||||
|
||||
await using (var writer = XmlWriter.Create(stream, settings))
|
||||
var writer = XmlWriter.Create(stream, settings);
|
||||
await using (writer.ConfigureAwait(false))
|
||||
{
|
||||
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
||||
await writer.WriteStartElementAsync(null, "tvshow", null).ConfigureAwait(false);
|
||||
@@ -1914,7 +1916,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
return;
|
||||
}
|
||||
|
||||
await using (var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
|
||||
var stream = new FileStream(nfoPath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||
await using (stream.ConfigureAwait(false))
|
||||
{
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
@@ -1927,7 +1930,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
|
||||
var isSeriesEpisode = timer.IsProgramSeries;
|
||||
|
||||
await using (var writer = XmlWriter.Create(stream, settings))
|
||||
var writer = XmlWriter.Create(stream, settings);
|
||||
await using (writer.ConfigureAwait(false))
|
||||
{
|
||||
await writer.WriteStartDocumentAsync(true).ConfigureAwait(false);
|
||||
|
||||
@@ -1965,7 +1969,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||
}
|
||||
else
|
||||
{
|
||||
await writer.WriteStartElementAsync(null, "movie", null);
|
||||
await writer.WriteStartElementAsync(null, "movie", null).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Name))
|
||||
{
|
||||
|
||||
@@ -106,8 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
options.Content = JsonContent.Create(requestList, options: _jsonOptions);
|
||||
options.Headers.TryAddWithoutValidation("token", token);
|
||||
using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
||||
await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var dailySchedules = await JsonSerializer.DeserializeAsync<IReadOnlyList<DayDto>>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
var dailySchedules = await response.Content.ReadFromJsonAsync<IReadOnlyList<DayDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
if (dailySchedules is null)
|
||||
{
|
||||
return Array.Empty<ProgramInfo>();
|
||||
@@ -122,8 +121,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
programRequestOptions.Content = JsonContent.Create(programIds, options: _jsonOptions);
|
||||
|
||||
using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
|
||||
await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var programDetails = await JsonSerializer.DeserializeAsync<IReadOnlyList<ProgramDetailsDto>>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
var programDetails = await innerResponse.Content.ReadFromJsonAsync<IReadOnlyList<ProgramDetailsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
if (programDetails is null)
|
||||
{
|
||||
return Array.Empty<ProgramInfo>();
|
||||
@@ -482,8 +480,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
try
|
||||
{
|
||||
using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
|
||||
await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
return await JsonSerializer.DeserializeAsync<IReadOnlyList<ShowImagesDto>>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return await innerResponse2.Content.ReadFromJsonAsync<IReadOnlyList<ShowImagesDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -510,10 +507,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
try
|
||||
{
|
||||
using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
|
||||
await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var root = await JsonSerializer.DeserializeAsync<IReadOnlyList<HeadendsDto>>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var root = await httpResponse.Content.ReadFromJsonAsync<IReadOnlyList<HeadendsDto>>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
if (root is not null)
|
||||
{
|
||||
foreach (HeadendsDto headend in root)
|
||||
@@ -649,8 +643,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
|
||||
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var root = await JsonSerializer.DeserializeAsync<TokenDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
var root = await response.Content.ReadFromJsonAsync<TokenDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
if (string.Equals(root?.Message, "OK", StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogInformation("Authenticated with Schedules Direct token: {Token}", root.Token);
|
||||
@@ -691,10 +684,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
{
|
||||
using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
using var response = httpResponse.Content;
|
||||
var root = await JsonSerializer.DeserializeAsync<LineupsDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var root = await httpResponse.Content.ReadFromJsonAsync<LineupsDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
return root?.Lineups.Any(i => string.Equals(info.ListingsId, i.Lineup, StringComparison.OrdinalIgnoreCase)) ?? false;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
@@ -748,8 +738,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
||||
options.Headers.TryAddWithoutValidation("token", token);
|
||||
|
||||
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
|
||||
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var root = await JsonSerializer.DeserializeAsync<ChannelDto>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
var root = await httpResponse.Content.ReadFromJsonAsync<ChannelDto>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
if (root is null)
|
||||
{
|
||||
return new List<ChannelInfo>();
|
||||
|
||||
@@ -17,7 +17,6 @@ using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -27,7 +28,6 @@ using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||
@@ -76,13 +76,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL ?? model.BaseURL + "/lineup.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, _jsonOptions, cancellationToken)
|
||||
.ConfigureAwait(false) ?? new List<Channels>();
|
||||
|
||||
var lineup = await response.Content.ReadFromJsonAsync<IEnumerable<Channels>>(_jsonOptions, cancellationToken).ConfigureAwait(false) ?? Enumerable.Empty<Channels>();
|
||||
if (info.ImportFavoritesOnly)
|
||||
{
|
||||
lineup = lineup.Where(i => i.Favorite).ToList();
|
||||
lineup = lineup.Where(i => i.Favorite);
|
||||
}
|
||||
|
||||
return lineup.Where(i => !i.DRM).ToList();
|
||||
@@ -129,9 +126,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||
.GetAsync(GetApiUrl(info) + "/discover.json", HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, _jsonOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var discoverResponse = await response.Content.ReadFromJsonAsync<DiscoverResponse>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(cacheKey))
|
||||
{
|
||||
@@ -175,34 +170,37 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
||||
.GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
|
||||
var tuners = new List<LiveTvTunerInfo>();
|
||||
await foreach (var line in sr.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
|
||||
await using (stream.ConfigureAwait(false))
|
||||
{
|
||||
string stripedLine = StripXML(line);
|
||||
if (stripedLine.Contains("Channel", StringComparison.Ordinal))
|
||||
using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
|
||||
await foreach (var line in sr.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
LiveTvTunerStatus status;
|
||||
var index = stripedLine.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
|
||||
var name = stripedLine.Substring(0, index - 1);
|
||||
var currentChannel = stripedLine.Substring(index + 7);
|
||||
if (string.Equals(currentChannel, "none", StringComparison.Ordinal))
|
||||
string stripedLine = StripXML(line);
|
||||
if (stripedLine.Contains("Channel", StringComparison.Ordinal))
|
||||
{
|
||||
status = LiveTvTunerStatus.LiveTv;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = LiveTvTunerStatus.Available;
|
||||
}
|
||||
LiveTvTunerStatus status;
|
||||
var index = stripedLine.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
|
||||
var name = stripedLine.Substring(0, index - 1);
|
||||
var currentChannel = stripedLine.Substring(index + 7);
|
||||
if (string.Equals(currentChannel, "none", StringComparison.Ordinal))
|
||||
{
|
||||
status = LiveTvTunerStatus.LiveTv;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = LiveTvTunerStatus.Available;
|
||||
}
|
||||
|
||||
tuners.Add(new LiveTvTunerInfo
|
||||
{
|
||||
Name = name,
|
||||
SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
|
||||
ProgramName = currentChannel,
|
||||
Status = status
|
||||
});
|
||||
tuners.Add(new LiveTvTunerInfo
|
||||
{
|
||||
Name = name,
|
||||
SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
|
||||
ProgramName = currentChannel,
|
||||
Status = status
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||
StopStreaming(socket).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public async Task<bool> CheckTunerAvailability(IPAddress remoteIP, int tuner, CancellationToken cancellationToken)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
@@ -22,7 +21,6 @@ using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
"TaskCleanLogsDescription": "Deletes log files that are more than {0} days old.",
|
||||
"TaskRefreshPeople": "Refresh People",
|
||||
"TaskRefreshPeopleDescription": "Updates metadata for actors and directors in your media library.",
|
||||
"TaskRefreshTrickplayImages": "Generate Trickplay Images",
|
||||
"TaskRefreshTrickplayImagesDescription": "Creates trickplay previews for videos in enabled libraries.",
|
||||
"TaskUpdatePlugins": "Update Plugins",
|
||||
"TaskUpdatePluginsDescription": "Downloads and installs updates for plugins that are configured to update automatically.",
|
||||
"TaskCleanTranscode": "Clean Transcode Directory",
|
||||
|
||||
18
Emby.Server.Implementations/Localization/Core/fo.json
Normal file
18
Emby.Server.Implementations/Localization/Core/fo.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"Artists": "Listafólk",
|
||||
"Collections": "Søvn",
|
||||
"Default": "Sjálvgildi",
|
||||
"DeviceOfflineWithName": "{0} hevur slitið sambandið",
|
||||
"External": "Ytri",
|
||||
"Genres": "Greinar",
|
||||
"Albums": "Album",
|
||||
"AppDeviceValues": "App: {0}, Eind: {1}",
|
||||
"Application": "Nýtsluskipan",
|
||||
"Books": "Bøkur",
|
||||
"Channels": "Rásir",
|
||||
"ChapterNameValue": "Kapittul {0}",
|
||||
"DeviceOnlineWithName": "{0} er sambundið",
|
||||
"Favorites": "Yndis",
|
||||
"Folders": "Mappur",
|
||||
"Forced": "Kravt"
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
"HeaderFavoriteArtists": "Uppáhalds Listamenn",
|
||||
"HeaderFavoriteAlbums": "Uppáhalds Plötur",
|
||||
"HeaderContinueWatching": "Halda áfram að horfa",
|
||||
"HeaderAlbumArtists": "Höfundur plötu",
|
||||
"Genres": "Tegundir",
|
||||
"HeaderAlbumArtists": "Listamaður á umslagi",
|
||||
"Genres": "Stefnur",
|
||||
"Folders": "Möppur",
|
||||
"Favorites": "Uppáhalds",
|
||||
"FailedLoginAttemptWithUserName": "{0} reyndi að auðkenna sig",
|
||||
@@ -22,32 +22,32 @@
|
||||
"DeviceOfflineWithName": "{0} hefur aftengst",
|
||||
"Collections": "Söfn",
|
||||
"ChapterNameValue": "Kafli {0}",
|
||||
"Channels": "Stöðvar",
|
||||
"CameraImageUploadedFrom": "Ný ljósmynd frá myndavél hefur verið hlaðið upp frá {0}",
|
||||
"Channels": "Rásir",
|
||||
"CameraImageUploadedFrom": "{0} hefur hlaðið upp nýrri ljósmynd úr myndavél sinni",
|
||||
"Books": "Bækur",
|
||||
"AuthenticationSucceededWithUserName": "{0} auðkenning tókst",
|
||||
"Artists": "Listamaður",
|
||||
"AuthenticationSucceededWithUserName": "Auðkenning fyrir {0} tókst",
|
||||
"Artists": "Listamenn",
|
||||
"Application": "Forrit",
|
||||
"AppDeviceValues": "Snjallforrit: {0}, Tæki: {1}",
|
||||
"Albums": "Plötur",
|
||||
"Plugin": "Viðbót",
|
||||
"Photos": "Myndir",
|
||||
"NotificationOptionVideoPlaybackStopped": "Myndbandafspilun stöðvuð",
|
||||
"NotificationOptionVideoPlayback": "Myndbandafspilun hafin",
|
||||
"Plugin": "Viðbótarvirkni",
|
||||
"Photos": "Ljósmyndir",
|
||||
"NotificationOptionVideoPlaybackStopped": "Myndbandsafspilun stöðvuð",
|
||||
"NotificationOptionVideoPlayback": "Myndbandsafspilun hafin",
|
||||
"NotificationOptionUserLockedOut": "Notandi læstur úti",
|
||||
"NotificationOptionServerRestartRequired": "Endurræsing þjóns er nauðsynileg",
|
||||
"NotificationOptionPluginUpdateInstalled": "Viðbótar uppfærsla uppsett",
|
||||
"NotificationOptionPluginUninstalled": "Viðbót fjarlægð",
|
||||
"NotificationOptionPluginInstalled": "Viðbót sett upp",
|
||||
"NotificationOptionServerRestartRequired": "Endurræsing þjóns er nauðsynleg",
|
||||
"NotificationOptionPluginUpdateInstalled": "Uppfærslu á viðbótarvirkni lokið",
|
||||
"NotificationOptionPluginUninstalled": "Viðbótarvirkni fjarlægð",
|
||||
"NotificationOptionPluginInstalled": "Viðbótarvirkni sett upp",
|
||||
"NotificationOptionPluginError": "Bilun í viðbót",
|
||||
"NotificationOptionInstallationFailed": "Uppsetning tókst ekki",
|
||||
"NotificationOptionCameraImageUploaded": "Myndavélarmynd hlaðið upp",
|
||||
"NotificationOptionCameraImageUploaded": "Ljósmynd hlaðið upp",
|
||||
"NotificationOptionAudioPlaybackStopped": "Hljóðafspilun stöðvuð",
|
||||
"NotificationOptionAudioPlayback": "Hljóðafspilun hafin",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Uppfærsla uppsett",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Uppfærsla í boði",
|
||||
"NameSeasonUnknown": "Sería óþekkt",
|
||||
"NameSeasonNumber": "Sería {0}",
|
||||
"NameSeasonUnknown": "Þáttaröð óþekkt",
|
||||
"NameSeasonNumber": "Þáttaröð {0}",
|
||||
"MixedContent": "Blandað efni",
|
||||
"MessageServerConfigurationUpdated": "Stillingar þjóns hafa verið uppfærðar",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin þjónn hefur verið uppfærður í {0}",
|
||||
@@ -57,24 +57,24 @@
|
||||
"User": "Notandi",
|
||||
"System": "Kerfi",
|
||||
"NotificationOptionNewLibraryContent": "Nýju efni bætt við",
|
||||
"NewVersionIsAvailable": "Ný útgáfa af Jellyfin þjón er fáanleg til niðurhals.",
|
||||
"NewVersionIsAvailable": "Ný útgáfa af Jellyfin þjón er tilbúin til niðurhals.",
|
||||
"NameInstallFailed": "{0} uppsetning mistókst",
|
||||
"MusicVideos": "Tónlistarmyndbönd",
|
||||
"Music": "Tónlist",
|
||||
"Movies": "Kvikmyndir",
|
||||
"UserDeletedWithName": "Notanda {0} hefur verið eytt",
|
||||
"UserCreatedWithName": "Notandi {0} hefur verið stofnaður",
|
||||
"TvShows": "Þættir",
|
||||
"TvShows": "Sjónvarpsþættir",
|
||||
"Sync": "Samstilla",
|
||||
"Songs": "Lög",
|
||||
"ServerNameNeedsToBeRestarted": "{0} þarf að endurræsa",
|
||||
"ServerNameNeedsToBeRestarted": "{0} þarf að vera endurræstur",
|
||||
"ScheduledTaskStartedWithName": "{0} hafin",
|
||||
"ScheduledTaskFailedWithName": "{0} mistókst",
|
||||
"PluginUpdatedWithName": "{0} var uppfært",
|
||||
"PluginUninstalledWithName": "{0} var fjarlægt",
|
||||
"PluginInstalledWithName": "{0} var sett upp",
|
||||
"NotificationOptionTaskFailed": "Tímasett verkefni mistókst",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin netþjónnin er að hlaðast. Vinsamlega prufaðu aftur fljótlega.",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin netþjónnin er að ræsa sig upp. Vinsamlegast reyndu aftur fljótlega.",
|
||||
"VersionNumber": "Útgáfa {0}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} hefur verið bætt við í gagnasafnið þitt",
|
||||
"UserStoppedPlayingItemWithValues": "{0} hefur lokið spilunar af {1} á {2}",
|
||||
@@ -83,14 +83,14 @@
|
||||
"UserPasswordChangedWithName": "Lykilorði fyrir notandann {0} hefur verið breytt",
|
||||
"UserOnlineFromDevice": "{0} hefur verið virkur síðan {1}",
|
||||
"UserOfflineFromDevice": "{0} hefur aftengst frá {1}",
|
||||
"UserLockedOutWithName": "Notanda {0} hefur verið heflaður aðgangur",
|
||||
"UserDownloadingItemWithValues": "{0} Hleður niður {1}",
|
||||
"UserLockedOutWithName": "Notandi {0} hefur verið læstur úti",
|
||||
"UserDownloadingItemWithValues": "{0} hleður niður {1}",
|
||||
"SubtitleDownloadFailureFromForItem": "Tókst ekki að hala niður skjátextum frá {0} til {1}",
|
||||
"ProviderValue": "Veitandi: {0}",
|
||||
"ProviderValue": "Efnisveita: {0}",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Stilling {0} hefur verið uppfærð á netþjón",
|
||||
"ValueSpecialEpisodeName": "Sérstakt - {0}",
|
||||
"Shows": "Sýningar",
|
||||
"Playlists": "Spilunarlisti",
|
||||
"ValueSpecialEpisodeName": "Sérstaktur - {0}",
|
||||
"Shows": "Þættir",
|
||||
"Playlists": "Efnisskrár",
|
||||
"TaskRefreshChannelsDescription": "Endurhlaða upplýsingum netrása.",
|
||||
"TaskRefreshChannels": "Endurhlaða Rásir",
|
||||
"TaskCleanTranscodeDescription": "Eyða umkóðuðum skrám sem eru meira en einum degi eldri.",
|
||||
@@ -116,5 +116,12 @@
|
||||
"TaskCleanLogsDescription": "Eyðir færslu skrám sem eru meira en {0} gömul.",
|
||||
"TaskCleanLogs": "Hreinsa færslu skrá",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Leitar á netinu að texta sem vantar miðað við uppsetningu lýsigagna.",
|
||||
"HearingImpaired": "Heyrnarskertur"
|
||||
"HearingImpaired": "Heyrnarskertur",
|
||||
"TaskOptimizeDatabaseDescription": "Þjappar gagnagrunni og bætir við lausu diskaplássi. Að keyra þessa aðgerð eftir skönnun safnsins, eða eftir einhverjar breytingar sem fela í sér gagnagrunnsbreytingar, gætu aukið hraðvirkni.",
|
||||
"TaskKeyframeExtractor": "Lykilrammaplokkari",
|
||||
"TaskKeyframeExtractorDescription": "Plokkar lykilramma úr myndbandsskrám til að búa til nákvæmari HLS uppskiptingarlista. Þetta verk getur tekið langan tíma.",
|
||||
"TaskRefreshChapterImages": "Plokka kafla-myndir",
|
||||
"TaskCleanActivityLogDescription": "Eyðir virkniskráningarfærslum sem hafa náð settum hámarksaldri.",
|
||||
"Forced": "Þvingað",
|
||||
"External": "Útvær"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ServerNameNeedsToBeRestarted": "{0} ir vajadzīgs restarts",
|
||||
"NotificationOptionTaskFailed": "Plānota uzdevuma kļūme",
|
||||
"HeaderRecordingGroups": "Ierakstu Grupas",
|
||||
"HeaderRecordingGroups": "Ierakstu grupas",
|
||||
"UserPolicyUpdatedWithName": "Lietotāju politika atjaunota priekš {0}",
|
||||
"SubtitleDownloadFailureFromForItem": "Subtitru lejupielāde no {0} priekš {1} neizdevās",
|
||||
"NotificationOptionVideoPlaybackStopped": "Video atskaņošana apturēta",
|
||||
@@ -14,7 +14,7 @@
|
||||
"Photos": "Attēli",
|
||||
"NotificationOptionUserLockedOut": "Lietotājs bloķēts",
|
||||
"LabelRunningTimeValue": "Garums: {0}",
|
||||
"Inherit": "Mantot",
|
||||
"Inherit": "Pārmantot",
|
||||
"AppDeviceValues": "Lietotne: {0}, Ierīce: {1}",
|
||||
"VersionNumber": "Versija {0}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} ir ticis pievienots jūsu multvides bibliotēkai",
|
||||
@@ -28,7 +28,7 @@
|
||||
"UserDeletedWithName": "Lietotājs {0} ir izdzēsts",
|
||||
"UserCreatedWithName": "Lietotājs {0} ir ticis izveidots",
|
||||
"User": "Lietotājs",
|
||||
"TvShows": "TV Raidījumi",
|
||||
"TvShows": "TV raidījumi",
|
||||
"Sync": "Sinhronizācija",
|
||||
"System": "Sistēma",
|
||||
"StartupEmbyServerIsLoading": "Jellyfin Serveris lādējas. Lūdzu mēģiniet vēlreiz pēc brīža.",
|
||||
@@ -38,11 +38,11 @@
|
||||
"PluginUninstalledWithName": "{0} tika noņemts",
|
||||
"PluginInstalledWithName": "{0} tika uzstādīts",
|
||||
"Plugin": "Paplašinājums",
|
||||
"Playlists": "Atskaņošanas Saraksti",
|
||||
"Playlists": "Atskaņošanas saraksti",
|
||||
"MixedContent": "Jaukts saturs",
|
||||
"HomeVideos": "Mājas Video",
|
||||
"HomeVideos": "Mājas video",
|
||||
"HeaderNextUp": "Nākamais",
|
||||
"ChapterNameValue": "Nodaļa {0}",
|
||||
"ChapterNameValue": "{0}. nodaļa",
|
||||
"Application": "Lietotne",
|
||||
"NotificationOptionServerRestartRequired": "Vajadzīgs servera restarts",
|
||||
"NotificationOptionPluginUpdateInstalled": "Paplašinājuma atjauninājums uzstādīts",
|
||||
@@ -56,14 +56,14 @@
|
||||
"NotificationOptionApplicationUpdateInstalled": "Lietotnes atjauninājums uzstādīts",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Lietotnes atjauninājums pieejams",
|
||||
"NewVersionIsAvailable": "Lejupielādei ir pieejama jauna Jellyfin Server versija.",
|
||||
"NameSeasonUnknown": "Nezināma Sezona",
|
||||
"NameSeasonNumber": "Sezona {0}",
|
||||
"NameSeasonUnknown": "Nezināma sezona",
|
||||
"NameSeasonNumber": "{0}. sezona",
|
||||
"NameInstallFailed": "{0} instalācija neizdevās",
|
||||
"MusicVideos": "Mūzikas video",
|
||||
"Music": "Mūzika",
|
||||
"Movies": "Filmas",
|
||||
"MessageServerConfigurationUpdated": "Servera konfigurācija ir tikusi atjaunota",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Servera konfigurācijas sadaļa {0} ir tikusi atjaunota",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Servera konfigurācijas sadaļa {0} tika atjaunota",
|
||||
"MessageApplicationUpdatedTo": "Jellyfin Server ir ticis atjaunots uz {0}",
|
||||
"MessageApplicationUpdated": "Jellyfin Server ir ticis atjaunots",
|
||||
"Latest": "Jaunākais",
|
||||
@@ -71,57 +71,57 @@
|
||||
"ItemRemovedWithName": "{0} tika noņemts no bibliotēkas",
|
||||
"ItemAddedWithName": "{0} tika pievienots bibliotēkai",
|
||||
"HeaderLiveTV": "Tiešraides TV",
|
||||
"HeaderContinueWatching": "Turpināt Skatīšanos",
|
||||
"HeaderAlbumArtists": "Albumu Izpildītāji",
|
||||
"HeaderContinueWatching": "Turpināt skatīšanos",
|
||||
"HeaderAlbumArtists": "Albumu izpildītāji",
|
||||
"Genres": "Žanri",
|
||||
"Folders": "Mapes",
|
||||
"Favorites": "Favorīti",
|
||||
"FailedLoginAttemptWithUserName": "Neizdevies pieslēgšanās mēģinājums no {0}",
|
||||
"DeviceOnlineWithName": "{0} ir pievienojies",
|
||||
"DeviceOfflineWithName": "{0} ir atvienojies",
|
||||
"Favorites": "Izlase",
|
||||
"FailedLoginAttemptWithUserName": "Neizdevies ieiešanas mēģinājums no {0}",
|
||||
"DeviceOnlineWithName": "Savienojums ar {0} ir izveidots",
|
||||
"DeviceOfflineWithName": "Savienojums ar {0} ir pārtraukts",
|
||||
"Collections": "Kolekcijas",
|
||||
"Channels": "Kanāli",
|
||||
"CameraImageUploadedFrom": "Jauns kameras attēls ir ticis augšupielādēts no {0}",
|
||||
"CameraImageUploadedFrom": "Jauns kameras attēls tika augšupielādēts no {0}",
|
||||
"Books": "Grāmatas",
|
||||
"Artists": "Izpildītāji",
|
||||
"Albums": "Albumi",
|
||||
"ProviderValue": "Provider: {0}",
|
||||
"HeaderFavoriteSongs": "Dziesmu Favorīti",
|
||||
"HeaderFavoriteShows": "Raidījumu Favorīti",
|
||||
"HeaderFavoriteEpisodes": "Episožu Favorīti",
|
||||
"HeaderFavoriteArtists": "Izpildītāju Favorīti",
|
||||
"HeaderFavoriteAlbums": "Albumu Favorīti",
|
||||
"TaskCleanCacheDescription": "Nodzēš keša datnes, kas vairs nav sistēmai vajadzīgas.",
|
||||
"TaskRefreshChapterImages": "Izvilkt Nodaļu Attēlus",
|
||||
"HeaderFavoriteSongs": "Dziesmu izlase",
|
||||
"HeaderFavoriteShows": "Raidījumu izlase",
|
||||
"HeaderFavoriteEpisodes": "Sēriju izlase",
|
||||
"HeaderFavoriteArtists": "Izpildītāju izlase",
|
||||
"HeaderFavoriteAlbums": "Albumu izlase",
|
||||
"TaskCleanCacheDescription": "Nodzēš kešatmiņas datnes, kas vairs nav sistēmai vajadzīgas.",
|
||||
"TaskRefreshChapterImages": "Izvilkt nodaļu attēlus",
|
||||
"TasksApplicationCategory": "Lietotne",
|
||||
"TasksLibraryCategory": "Bibliotēka",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Internetā meklē trūkstošus subtitrus balstoties uz metadatu uzstādījumiem.",
|
||||
"TaskDownloadMissingSubtitles": "Lejupielādēt trūkstošus subtitrus",
|
||||
"TaskDownloadMissingSubtitles": "Lejupielādēt trūkstošos subtitrus",
|
||||
"TaskRefreshChannelsDescription": "Atjauno interneta kanālu informāciju.",
|
||||
"TaskRefreshChannels": "Atjaunot Kanālus",
|
||||
"TaskCleanTranscodeDescription": "Izdzēš trans-kodēšanas datnes, kas ir vecākas par vienu dienu.",
|
||||
"TaskCleanTranscode": "Iztīrīt Trans-kodēšanas Mapi",
|
||||
"TaskRefreshChannels": "Atjaunot kanālus",
|
||||
"TaskCleanTranscodeDescription": "Izdzēš transkodēšanas datnes, kas ir senākas par vienu dienu.",
|
||||
"TaskCleanTranscode": "Iztīrīt transkodēšanas mapi",
|
||||
"TaskUpdatePluginsDescription": "Lejupielādē un uzstāda atjauninājumus paplašinājumiem, kam ir uzstādīta automātiskā atjaunināšana.",
|
||||
"TaskUpdatePlugins": "Atjaunot Paplašinājumus",
|
||||
"TaskUpdatePlugins": "Atjaunot paplašinājumus",
|
||||
"TaskRefreshPeopleDescription": "Atjauno metadatus aktieriem un direktoriem jūsu multivides bibliotēkā.",
|
||||
"TaskRefreshPeople": "Atjaunot Cilvēkus",
|
||||
"TaskCleanLogsDescription": "Nodzēš log datnes, kas ir vairāk par {0} dienām vecas.",
|
||||
"TaskCleanLogs": "Iztīrīt Logdatņu Mapi",
|
||||
"TaskRefreshPeople": "Atjaunot cilvēkus",
|
||||
"TaskCleanLogsDescription": "Nodzēš logdatnes, kas ir senākas par {0} dienām.",
|
||||
"TaskCleanLogs": "Iztīrīt logdatņu mapi",
|
||||
"TaskRefreshLibraryDescription": "Skenē jūsu multivides bibliotēku, lai atrastu jaunas datnes, un atsvaidzina metadatus.",
|
||||
"TaskRefreshLibrary": "Skenēt Multivides Bibliotēku",
|
||||
"TaskRefreshLibrary": "Skenēt multivides bibliotēku",
|
||||
"TaskRefreshChapterImagesDescription": "Izveido sīktēlus priekš video ar sadaļām.",
|
||||
"TaskCleanCache": "Iztīrīt Kešošanas Mapi",
|
||||
"TasksChannelsCategory": "Interneta Kanāli",
|
||||
"TaskCleanCache": "Iztīrīt kešatmiņas mapi",
|
||||
"TasksChannelsCategory": "Interneta kanāli",
|
||||
"TasksMaintenanceCategory": "Apkope",
|
||||
"Forced": "Piespiests",
|
||||
"Forced": "Piespiedu",
|
||||
"TaskCleanActivityLogDescription": "Nodzēš darbību žurnāla ierakstus, kuri ir vecāki par doto vecumu.",
|
||||
"TaskCleanActivityLog": "Notīrīt Darbību Žurnālu",
|
||||
"TaskCleanActivityLog": "Notīrīt darbību žurnālu",
|
||||
"Undefined": "Nenoteikts",
|
||||
"Default": "Noklusējuma",
|
||||
"TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Uzdevum palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.",
|
||||
"TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Šī uzdevuma palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.",
|
||||
"TaskOptimizeDatabase": "Optimizēt datubāzi",
|
||||
"External": "Ārējais",
|
||||
"HearingImpaired": "Ar dzirdes traucējumiem",
|
||||
"TaskKeyframeExtractor": "Atslēgkadru Ekstraktors",
|
||||
"TaskKeyframeExtractor": "Atslēgkadru ekstraktors",
|
||||
"TaskKeyframeExtractorDescription": "Ekstraktē atslēgkadrus no video failiem lai izveidotu precīzākus HLS atskaņošanas sarakstus. Šis process var būt ilgs."
|
||||
}
|
||||
|
||||
@@ -121,5 +121,7 @@
|
||||
"TaskOptimizeDatabaseDescription": "ഡാറ്റാബേസ് ചുരുക്കുകയും സ്വതന്ത്ര ഇടം വെട്ടിച്ചുരുക്കുകയും ചെയ്യുന്നു. ലൈബ്രറി സ്കാൻ ചെയ്തതിനുശേഷം അല്ലെങ്കിൽ ഡാറ്റാബേസ് പരിഷ്ക്കരണങ്ങളെ സൂചിപ്പിക്കുന്ന മറ്റ് മാറ്റങ്ങൾ ചെയ്തതിന് ശേഷം ഈ ടാസ്ക് പ്രവർത്തിപ്പിക്കുന്നത് പ്രകടനം മെച്ചപ്പെടുത്തും.",
|
||||
"TaskOptimizeDatabase": "ഡാറ്റാബേസ് ഒപ്റ്റിമൈസ് ചെയ്യുക",
|
||||
"HearingImpaired": "കേൾവി തകരാറുകൾ",
|
||||
"External": "പുറമേയുള്ള"
|
||||
"External": "പുറമേയുള്ള",
|
||||
"TaskKeyframeExtractorDescription": "കൂടുതൽ കൃത്യമായ HLS പ്ലേലിസ്റ്റുകൾ സൃഷ്ടിക്കുന്നതിന് വീഡിയോ ഫയലുകളിൽ നിന്ന് കീഫ്രെയിമുകൾ എക്സ്ട്രാക്റ്റ് ചെയ്യുന്നു. ഈ പ്രവർത്തനം പൂർത്തിയാവാൻ കുറച്ചധികം സമയം എടുത്തേക്കാം.",
|
||||
"TaskKeyframeExtractor": "കീഫ്രെയിം എക്സ്ട്രാക്റ്റർ"
|
||||
}
|
||||
|
||||
1
Emby.Server.Implementations/Localization/Core/si.json
Normal file
1
Emby.Server.Implementations/Localization/Core/si.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -124,5 +124,5 @@
|
||||
"TaskKeyframeExtractorDescription": "Extrahuje kľúčové snímky z video súborov na vytvorenie presnejších HLS playlistov. Táto úloha môže trvať dlhšiu dobu.",
|
||||
"TaskKeyframeExtractor": "Extraktor kľúčových snímkov",
|
||||
"External": "Externé",
|
||||
"HearingImpaired": "Sluchovo Postihnutý"
|
||||
"HearingImpaired": "Sluchovo postihnutí"
|
||||
}
|
||||
|
||||
@@ -71,25 +71,28 @@ namespace Emby.Server.Implementations.Localization
|
||||
string countryCode = resource.Substring(RatingsPath.Length, 2);
|
||||
var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
await using var stream = _assembly.GetManifestResourceStream(resource);
|
||||
using var reader = new StreamReader(stream!); // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
var stream = _assembly.GetManifestResourceStream(resource);
|
||||
await using (stream!.ConfigureAwait(false)) // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
using var reader = new StreamReader(stream!);
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] parts = line.Split(',');
|
||||
if (parts.Length == 2
|
||||
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||
{
|
||||
var name = parts[0];
|
||||
dict.Add(name, new ParentalRating(name, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
||||
string[] parts = line.Split(',');
|
||||
if (parts.Length == 2
|
||||
&& int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
||||
{
|
||||
var name = parts[0];
|
||||
dict.Add(name, new ParentalRating(name, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Emby.Server.Implementations.MediaEncoder
|
||||
{
|
||||
var deadImages = images
|
||||
.Except(chapters.Select(i => i.ImagePath).Where(i => !string.IsNullOrEmpty(i)), StringComparer.OrdinalIgnoreCase)
|
||||
.Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
|
||||
.Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i.AsSpan()), StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach (var image in deadImages)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Emby.Server.Implementations.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory class to create different kinds of sockets.
|
||||
/// </summary>
|
||||
public class SocketFactory : ISocketFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@@ -29,7 +32,7 @@ namespace Emby.Server.Implementations.Net
|
||||
}
|
||||
catch
|
||||
{
|
||||
socket?.Dispose();
|
||||
socket.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
@@ -38,7 +41,8 @@ namespace Emby.Server.Implementations.Net
|
||||
/// <inheritdoc />
|
||||
public Socket CreateSsdpUdpSocket(IPData bindInterface, int localPort)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(bindInterface.Address);
|
||||
var interfaceAddress = bindInterface.Address;
|
||||
ArgumentNullException.ThrowIfNull(interfaceAddress);
|
||||
|
||||
if (localPort < 0)
|
||||
{
|
||||
@@ -49,13 +53,13 @@ namespace Emby.Server.Implementations.Net
|
||||
try
|
||||
{
|
||||
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
socket.Bind(new IPEndPoint(bindInterface.Address, localPort));
|
||||
socket.Bind(new IPEndPoint(interfaceAddress, localPort));
|
||||
|
||||
return socket;
|
||||
}
|
||||
catch
|
||||
{
|
||||
socket?.Dispose();
|
||||
socket.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
@@ -82,22 +86,31 @@ namespace Emby.Server.Implementations.Net
|
||||
|
||||
try
|
||||
{
|
||||
var interfaceIndex = bindInterface.Index;
|
||||
var interfaceIndexSwapped = (int)IPAddress.HostToNetworkOrder(interfaceIndex);
|
||||
|
||||
socket.MulticastLoopback = false;
|
||||
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, interfaceIndexSwapped);
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, interfaceIndex));
|
||||
socket.Bind(new IPEndPoint(multicastAddress, localPort));
|
||||
|
||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
{
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress));
|
||||
socket.Bind(new IPEndPoint(multicastAddress, localPort));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only create socket if interface supports multicast
|
||||
var interfaceIndex = bindInterface.Index;
|
||||
var interfaceIndexSwapped = IPAddress.HostToNetworkOrder(interfaceIndex);
|
||||
|
||||
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, interfaceIndex));
|
||||
socket.Bind(new IPEndPoint(bindIPAddress, localPort));
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
catch
|
||||
{
|
||||
socket?.Dispose();
|
||||
socket.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -327,9 +327,9 @@ namespace Emby.Server.Implementations.Playlists
|
||||
// this is probably best done as a metadata provider
|
||||
// saving a file over itself will require some work to prevent this from happening when not needed
|
||||
var playlistPath = item.Path;
|
||||
var extension = Path.GetExtension(playlistPath);
|
||||
var extension = Path.GetExtension(playlistPath.AsSpan());
|
||||
|
||||
if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase))
|
||||
if (extension.Equals(".wpl", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var playlist = new WplPlaylist();
|
||||
foreach (var child in item.GetLinkedChildren())
|
||||
@@ -362,8 +362,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||
string text = new WplContent().ToText(playlist);
|
||||
File.WriteAllText(playlistPath, text);
|
||||
}
|
||||
|
||||
if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase))
|
||||
else if (extension.Equals(".zpl", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var playlist = new ZplPlaylist();
|
||||
foreach (var child in item.GetLinkedChildren())
|
||||
@@ -396,8 +395,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||
string text = new ZplContent().ToText(playlist);
|
||||
File.WriteAllText(playlistPath, text);
|
||||
}
|
||||
|
||||
if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase))
|
||||
else if (extension.Equals(".m3u", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var playlist = new M3uPlaylist
|
||||
{
|
||||
@@ -428,8 +426,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||
string text = new M3uContent().ToText(playlist);
|
||||
File.WriteAllText(playlistPath, text);
|
||||
}
|
||||
|
||||
if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase))
|
||||
else if (extension.Equals(".m3u8", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var playlist = new M3uPlaylist();
|
||||
playlist.IsExtended = true;
|
||||
@@ -458,8 +455,7 @@ namespace Emby.Server.Implementations.Playlists
|
||||
string text = new M3uContent().ToText(playlist);
|
||||
File.WriteAllText(playlistPath, text);
|
||||
}
|
||||
|
||||
if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase))
|
||||
else if (extension.Equals(".pls", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var playlist = new PlsPlaylist();
|
||||
foreach (var child in item.GetLinkedChildren())
|
||||
|
||||
@@ -386,11 +386,11 @@ namespace Emby.Server.Implementations.Plugins
|
||||
var url = new Uri(packageInfo.ImageUrl);
|
||||
imagePath = Path.Join(path, url.Segments[^1]);
|
||||
|
||||
await using var fileStream = AsyncFile.OpenWrite(imagePath);
|
||||
|
||||
var fileStream = AsyncFile.OpenWrite(imagePath);
|
||||
Stream? downloadStream = null;
|
||||
try
|
||||
{
|
||||
await using var downloadStream = await HttpClientFactory
|
||||
downloadStream = await HttpClientFactory
|
||||
.CreateClient(NamedClient.Default)
|
||||
.GetStreamAsync(url)
|
||||
.ConfigureAwait(false);
|
||||
@@ -402,6 +402,14 @@ namespace Emby.Server.Implementations.Plugins
|
||||
_logger.LogError(ex, "Failed to download image to path {Path} on disk.", imagePath);
|
||||
imagePath = string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await fileStream.DisposeAsync().ConfigureAwait(false);
|
||||
if (downloadStream is not null)
|
||||
{
|
||||
await downloadStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var manifest = new PluginManifest
|
||||
@@ -421,7 +429,7 @@ namespace Emby.Server.Implementations.Plugins
|
||||
ImagePath = imagePath
|
||||
};
|
||||
|
||||
if (!await ReconcileManifest(manifest, path))
|
||||
if (!await ReconcileManifest(manifest, path).ConfigureAwait(false))
|
||||
{
|
||||
// An error occurred during reconciliation and saving could be undesirable.
|
||||
return false;
|
||||
@@ -458,7 +466,7 @@ namespace Emby.Server.Implementations.Plugins
|
||||
}
|
||||
|
||||
using var metaStream = File.OpenRead(metafile);
|
||||
var localManifest = await JsonSerializer.DeserializeAsync<PluginManifest>(metaStream, _jsonOptions);
|
||||
var localManifest = await JsonSerializer.DeserializeAsync<PluginManifest>(metaStream, _jsonOptions).ConfigureAwait(false);
|
||||
localManifest ??= new PluginManifest();
|
||||
|
||||
if (!Equals(localManifest.Id, manifest.Id))
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
previouslyFailedImages = File.ReadAllText(failHistoryPath)
|
||||
previouslyFailedImages = (await File.ReadAllTextAsync(failHistoryPath, cancellationToken).ConfigureAwait(false))
|
||||
.Split('|', StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToList();
|
||||
}
|
||||
@@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
|
||||
}
|
||||
|
||||
string text = string.Join('|', previouslyFailedImages);
|
||||
File.WriteAllText(failHistoryPath, text);
|
||||
await File.WriteAllTextAsync(failHistoryPath, text, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
|
||||
104
Emby.Server.Implementations/SystemManager.cs
Normal file
104
Emby.Server.Implementations/SystemManager.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Model.System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Emby.Server.Implementations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class SystemManager : ISystemManager
|
||||
{
|
||||
private readonly IHostApplicationLifetime _applicationLifetime;
|
||||
private readonly IServerApplicationHost _applicationHost;
|
||||
private readonly IServerApplicationPaths _applicationPaths;
|
||||
private readonly IServerConfigurationManager _configurationManager;
|
||||
private readonly IStartupOptions _startupOptions;
|
||||
private readonly IInstallationManager _installationManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SystemManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationLifetime">Instance of <see cref="IHostApplicationLifetime"/>.</param>
|
||||
/// <param name="applicationHost">Instance of <see cref="IServerApplicationHost"/>.</param>
|
||||
/// <param name="applicationPaths">Instance of <see cref="IServerApplicationPaths"/>.</param>
|
||||
/// <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>
|
||||
public SystemManager(
|
||||
IHostApplicationLifetime applicationLifetime,
|
||||
IServerApplicationHost applicationHost,
|
||||
IServerApplicationPaths applicationPaths,
|
||||
IServerConfigurationManager configurationManager,
|
||||
IStartupOptions startupOptions,
|
||||
IInstallationManager installationManager)
|
||||
{
|
||||
_applicationLifetime = applicationLifetime;
|
||||
_applicationHost = applicationHost;
|
||||
_applicationPaths = applicationPaths;
|
||||
_configurationManager = configurationManager;
|
||||
_startupOptions = startupOptions;
|
||||
_installationManager = installationManager;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SystemInfo GetSystemInfo(HttpRequest request)
|
||||
{
|
||||
return new SystemInfo
|
||||
{
|
||||
HasPendingRestart = _applicationHost.HasPendingRestart,
|
||||
IsShuttingDown = _applicationLifetime.ApplicationStopping.IsCancellationRequested,
|
||||
Version = _applicationHost.ApplicationVersionString,
|
||||
WebSocketPortNumber = _applicationHost.HttpPort,
|
||||
CompletedInstallations = _installationManager.CompletedInstallations.ToArray(),
|
||||
Id = _applicationHost.SystemId,
|
||||
ProgramDataPath = _applicationPaths.ProgramDataPath,
|
||||
WebPath = _applicationPaths.WebPath,
|
||||
LogPath = _applicationPaths.LogDirectoryPath,
|
||||
ItemsByNamePath = _applicationPaths.InternalMetadataPath,
|
||||
InternalMetadataPath = _applicationPaths.InternalMetadataPath,
|
||||
CachePath = _applicationPaths.CachePath,
|
||||
TranscodingTempPath = _configurationManager.GetTranscodePath(),
|
||||
ServerName = _applicationHost.FriendlyName,
|
||||
LocalAddress = _applicationHost.GetSmartApiUrl(request),
|
||||
SupportsLibraryMonitor = true,
|
||||
PackageName = _startupOptions.PackageName,
|
||||
CastReceiverApplications = _configurationManager.Configuration.CastReceiverApplications
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublicSystemInfo GetPublicSystemInfo(HttpRequest request)
|
||||
{
|
||||
return new PublicSystemInfo
|
||||
{
|
||||
Version = _applicationHost.ApplicationVersionString,
|
||||
ProductName = _applicationHost.Name,
|
||||
Id = _applicationHost.SystemId,
|
||||
ServerName = _applicationHost.FriendlyName,
|
||||
LocalAddress = _applicationHost.GetSmartApiUrl(request),
|
||||
StartupWizardCompleted = _configurationManager.CommonConfiguration.IsStartupWizardCompleted
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Restart() => ShutdownInternal(true);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Shutdown() => ShutdownInternal(false);
|
||||
|
||||
private void ShutdownInternal(bool restart)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
_applicationHost.ShouldRestart = restart;
|
||||
_applicationLifetime.StopApplication();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,9 @@ namespace Emby.Server.Implementations.Udp
|
||||
|
||||
private readonly byte[] _receiveBuffer = new byte[8192];
|
||||
|
||||
private Socket _udpSocket;
|
||||
private IPEndPoint _endpoint;
|
||||
private bool _disposed = false;
|
||||
private readonly Socket _udpSocket;
|
||||
private readonly IPEndPoint _endpoint;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UdpServer" /> class.
|
||||
@@ -52,7 +52,10 @@ namespace Emby.Server.Implementations.Udp
|
||||
|
||||
_endpoint = new IPEndPoint(bindAddress, port);
|
||||
|
||||
_udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
_udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
|
||||
{
|
||||
MulticastLoopback = false,
|
||||
};
|
||||
_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
}
|
||||
|
||||
@@ -74,6 +77,7 @@ namespace Emby.Server.Implementations.Udp
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogDebug("Sending AutoDiscovery response");
|
||||
await _udpSocket.SendToAsync(JsonSerializer.SerializeToUtf8Bytes(response), SocketFlags.None, endpoint, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
@@ -99,7 +103,8 @@ namespace Emby.Server.Implementations.Udp
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _udpSocket.ReceiveFromAsync(_receiveBuffer, SocketFlags.None, _endpoint, cancellationToken).ConfigureAwait(false);
|
||||
var endpoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
|
||||
var result = await _udpSocket.ReceiveFromAsync(_receiveBuffer, endpoint, cancellationToken).ConfigureAwait(false);
|
||||
var text = Encoding.UTF8.GetString(_receiveBuffer, 0, result.ReceivedBytes);
|
||||
if (text.Contains("who is JellyfinServer?", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -112,7 +117,7 @@ namespace Emby.Server.Implementations.Udp
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Don't throw
|
||||
_logger.LogDebug("Broadcast socket operation cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,9 +130,8 @@ namespace Emby.Server.Implementations.Udp
|
||||
return;
|
||||
}
|
||||
|
||||
_udpSocket?.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_udpSocket.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,8 +504,7 @@ namespace Emby.Server.Implementations.Updates
|
||||
|
||||
private async Task PerformPackageInstallation(InstallationInfo package, PluginStatus status, CancellationToken cancellationToken)
|
||||
{
|
||||
var extension = Path.GetExtension(package.SourceUrl);
|
||||
if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase))
|
||||
if (!Path.GetExtension(package.SourceUrl.AsSpan()).Equals(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_logger.LogError("Only zip packages are supported. {SourceUrl} is not a zip archive.", package.SourceUrl);
|
||||
return;
|
||||
@@ -521,10 +520,9 @@ namespace Emby.Server.Implementations.Updates
|
||||
|
||||
// CA5351: Do Not Use Broken Cryptographic Algorithms
|
||||
#pragma warning disable CA5351
|
||||
using var md5 = MD5.Create();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var hash = Convert.ToHexString(md5.ComputeHash(stream));
|
||||
var hash = Convert.ToHexString(await MD5.HashDataAsync(stream, cancellationToken).ConfigureAwait(false));
|
||||
if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_logger.LogError(
|
||||
@@ -557,7 +555,7 @@ namespace Emby.Server.Implementations.Updates
|
||||
reader.ExtractToDirectory(targetDir, true);
|
||||
|
||||
// Ensure we create one or populate existing ones with missing data.
|
||||
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status);
|
||||
await _pluginManager.PopulateManifest(package.PackageInfo, package.Version, targetDir, status).ConfigureAwait(false);
|
||||
|
||||
_pluginManager.ImportPluginFrom(targetDir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user