diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs
index 140ef9b46..243b09786 100644
--- a/Emby.Dlna/ControlResponse.cs
+++ b/Emby.Dlna/ControlResponse.cs
@@ -16,5 +16,11 @@ namespace Emby.Dlna
public string Xml { get; set; }
public bool IsSuccessful { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ return Xml;
+ }
}
}
diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
index 0b681fddf..4c9ab33a7 100644
--- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
+++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
@@ -1,3 +1,5 @@
+#nullable enable
+
using System;
using System.IO;
using System.Linq;
@@ -22,7 +24,7 @@ namespace Emby.Server.Implementations.AppBase
{
object configuration;
- byte[] buffer = null;
+ byte[]? buffer = null;
// Use try/catch to avoid the extra file system lookup using File.Exists
try
@@ -36,19 +38,23 @@ namespace Emby.Server.Implementations.AppBase
configuration = Activator.CreateInstance(type);
}
- using var stream = new MemoryStream();
+ using var stream = new MemoryStream(buffer?.Length ?? 0);
xmlSerializer.SerializeToStream(configuration, stream);
// Take the object we just got and serialize it back to bytes
- var newBytes = stream.ToArray();
+ byte[] newBytes = stream.GetBuffer();
+ int newBytesLen = (int)stream.Length;
// If the file didn't exist before, or if something has changed, re-save
- if (buffer == null || !buffer.SequenceEqual(newBytes))
+ if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer))
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
// Save it after load in case we got new items
- File.WriteAllBytes(path, newBytes);
+ using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+ {
+ fs.Write(newBytes, 0, newBytesLen);
+ }
}
return configuration;
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index ff7ee085f..64ccff53b 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using Emby.Server.Implementations.HttpServer;
-using Emby.Server.Implementations.Updates;
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
namespace Emby.Server.Implementations
@@ -19,7 +18,8 @@ namespace Emby.Server.Implementations
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" },
- { PlaylistsAllowDuplicatesKey, bool.TrueString }
+ { PlaylistsAllowDuplicatesKey, bool.TrueString },
+ { BindToUnixSocketKey, bool.FalseString }
};
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index c967e9230..f2c7118fe 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -73,25 +73,6 @@ namespace Emby.Server.Implementations.Dto
_livetvManagerFactory = livetvManagerFactory;
}
- ///
- /// Converts a BaseItem to a DTOBaseItem.
- ///
- /// The item.
- /// The fields.
- /// The user.
- /// The owner.
- /// Task{DtoBaseItem}.
- /// item
- public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null)
- {
- var options = new DtoOptions
- {
- Fields = fields
- };
-
- return GetBaseItemDto(item, options, user, owner);
- }
-
///
public IReadOnlyList GetBaseItemDtos(IReadOnlyList items, DtoOptions options, User user = null, BaseItem owner = null)
{
@@ -443,17 +424,6 @@ namespace Emby.Server.Implementations.Dto
return folder.GetChildCount(user);
}
- ///
- /// Gets client-side Id of a server-side BaseItem.
- ///
- /// The item.
- /// System.String.
- /// item
- public string GetDtoId(BaseItem item)
- {
- return item.Id.ToString("N", CultureInfo.InvariantCulture);
- }
-
private static void SetBookProperties(BaseItemDto dto, Book item)
{
dto.SeriesName = item.SeriesName;
@@ -484,6 +454,11 @@ namespace Emby.Server.Implementations.Dto
}
}
+ private string GetDtoId(BaseItem item)
+ {
+ return item.Id.ToString("N", CultureInfo.InvariantCulture);
+ }
+
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
{
if (!string.IsNullOrEmpty(item.Album))
@@ -513,19 +488,6 @@ namespace Emby.Server.Implementations.Dto
.ToArray();
}
- private string GetImageCacheTag(BaseItem item, ImageType type)
- {
- try
- {
- return _imageProcessor.GetImageCacheTag(item, type);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting {type} image info", type);
- return null;
- }
- }
-
private string GetImageCacheTag(BaseItem item, ItemImageInfo image)
{
try
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 970f5119c..688216373 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary();
}
- if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string expires))
+ if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out _))
{
responseHeaders[HeaderNames.Expires] = "0";
}
@@ -326,7 +326,8 @@ namespace Emby.Server.Implementations.HttpServer
return GetHttpResult(request, ms, contentType, true, responseHeaders);
}
- private IHasHeaders GetCompressedResult(byte[] content,
+ private IHasHeaders GetCompressedResult(
+ byte[] content,
string requestedCompressionType,
IDictionary responseHeaders,
bool isHeadRequest,
diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
index 5afc51dbc..00e3ab8fe 100644
--- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
@@ -95,13 +95,13 @@ namespace Emby.Server.Implementations.HttpServer
if (bytes != null)
{
- await responseStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ await responseStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
}
else
{
using (var src = SourceStream)
{
- await src.CopyToAsync(responseStream).ConfigureAwait(false);
+ await src.CopyToAsync(responseStream, cancellationToken).ConfigureAwait(false);
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index f3fc41352..8a0c0043a 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -19,8 +19,7 @@ namespace Emby.Server.Implementations.LiveTv
public class LiveTvMediaSourceProvider : IMediaSourceProvider
{
// Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
- private const char StreamIdDelimeter = '_';
- private const string StreamIdDelimeterString = "_";
+ private const char StreamIdDelimiter = '_';
private readonly ILiveTvManager _liveTvManager;
private readonly ILogger _logger;
@@ -47,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- return Task.FromResult>(Array.Empty());
+ return Task.FromResult(Enumerable.Empty());
}
private async Task> GetMediaSourcesInternal(BaseItem item, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
@@ -98,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv
source.Id ?? string.Empty
};
- source.OpenToken = string.Join(StreamIdDelimeterString, openKeys);
+ source.OpenToken = string.Join(StreamIdDelimiter, openKeys);
}
// Dummy this up so that direct play checks can still run
@@ -116,7 +115,7 @@ namespace Emby.Server.Implementations.LiveTv
///
public async Task OpenMediaSource(string openToken, List currentLiveStreams, CancellationToken cancellationToken)
{
- var keys = openToken.Split(new[] { StreamIdDelimeter }, 3);
+ var keys = openToken.Split(StreamIdDelimiter, 3);
var mediaSourceId = keys.Length >= 3 ? keys[2] : null;
var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, currentLiveStreams, cancellationToken).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index a8d34d19c..fbcd4ef37 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -1,10 +1,10 @@
#pragma warning disable CS1591
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -14,7 +14,7 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
@@ -23,17 +23,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
protected readonly IServerConfigurationManager Config;
protected readonly ILogger Logger;
- protected IJsonSerializer JsonSerializer;
protected readonly IFileSystem FileSystem;
- private readonly ConcurrentDictionary _channelCache =
- new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+ private readonly IMemoryCache _memoryCache;
- protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
+ protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IFileSystem fileSystem, IMemoryCache memoryCache)
{
Config = config;
Logger = logger;
- JsonSerializer = jsonSerializer;
+ _memoryCache = memoryCache;
FileSystem = fileSystem;
}
@@ -44,23 +42,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken)
{
- ChannelCache cache = null;
var key = tuner.Id;
- if (enableCache && !string.IsNullOrEmpty(key) && _channelCache.TryGetValue(key, out cache))
+ if (enableCache && !string.IsNullOrEmpty(key) && _memoryCache.TryGetValue(key, out List cache))
{
- return cache.Channels.ToList();
+ return cache;
}
- var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
- var list = result.ToList();
+ var list = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
// logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
if (!string.IsNullOrEmpty(key) && list.Count > 0)
{
- cache = cache ?? new ChannelCache();
- cache.Channels = list;
- _channelCache.AddOrUpdate(key, cache, (k, v) => cache);
+ _memoryCache.Set(key, list);
}
return list;
@@ -95,7 +89,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
try
{
Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile));
- JsonSerializer.SerializeToFile(channels, channelCacheFile);
+ await using var writeStream = File.OpenWrite(channelCacheFile);
+ await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
@@ -110,7 +105,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
try
{
- var channels = JsonSerializer.DeserializeFromFile>(channelCacheFile);
+ await using var readStream = File.OpenRead(channelCacheFile);
+ var channels = await JsonSerializer.DeserializeAsync>(readStream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
list.AddRange(channels);
}
catch (IOException)
@@ -233,10 +230,5 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
return Config.GetConfiguration("livetv");
}
-
- private class ChannelCache
- {
- public List Channels;
- }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 00420bd2a..c61189c0a 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -23,7 +24,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
@@ -39,14 +40,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public HdHomerunHost(
IServerConfigurationManager config,
ILogger logger,
- IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
IHttpClient httpClient,
IServerApplicationHost appHost,
ISocketFactory socketFactory,
INetworkManager networkManager,
- IStreamHelper streamHelper)
- : base(config, logger, jsonSerializer, fileSystem)
+ IStreamHelper streamHelper,
+ IMemoryCache memoryCache)
+ : base(config, logger, fileSystem, memoryCache)
{
_httpClient = httpClient;
_appHost = appHost;
@@ -75,18 +76,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BufferContent = false
};
- using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
+ using var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
+ await using var stream = response.Content;
+ var lineup = await JsonSerializer.DeserializeAsync>(stream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false) ?? new List();
+
+ if (info.ImportFavoritesOnly)
{
- var lineup = await JsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false) ?? new List();
-
- if (info.ImportFavoritesOnly)
- {
- lineup = lineup.Where(i => i.Favorite).ToList();
- }
-
- return lineup.Where(i => !i.DRM).ToList();
+ lineup = lineup.Where(i => i.Favorite).ToList();
}
+
+ return lineup.Where(i => !i.DRM).ToList();
}
private class HdHomerunChannelInfo : ChannelInfo
@@ -132,30 +132,30 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions()
+ using var response = await _httpClient.SendAsync(
+ new HttpRequestOptions
{
- Url = string.Format("{0}/discover.json", GetApiUrl(info)),
+ Url = string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)),
CancellationToken = cancellationToken,
BufferContent = false
- }, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
+ }, HttpMethod.Get).ConfigureAwait(false);
+ await using var stream = response.Content;
+ var discoverResponse = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
+
+ if (!string.IsNullOrEmpty(cacheKey))
{
- var discoverResponse = await JsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false);
-
- if (!string.IsNullOrEmpty(cacheKey))
+ lock (_modelCache)
{
- lock (_modelCache)
- {
- _modelCache[cacheKey] = discoverResponse;
- }
+ _modelCache[cacheKey] = discoverResponse;
}
-
- return discoverResponse;
}
+
+ return discoverResponse;
}
catch (HttpException ex)
{
- if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
+ if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
{
var defaultValue = "HDHR";
var response = new DiscoverResponse
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index ff42a9747..8fc29fb4a 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -18,7 +18,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -36,13 +36,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
IServerConfigurationManager config,
IMediaSourceManager mediaSourceManager,
ILogger logger,
- IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
IHttpClient httpClient,
IServerApplicationHost appHost,
INetworkManager networkManager,
- IStreamHelper streamHelper)
- : base(config, logger, jsonSerializer, fileSystem)
+ IStreamHelper streamHelper,
+ IMemoryCache memoryCache)
+ : base(config, logger, fileSystem, memoryCache)
{
_httpClient = httpClient;
_appHost = appHost;
diff --git a/Emby.Server.Implementations/Localization/Core/bn.json b/Emby.Server.Implementations/Localization/Core/bn.json
index ca14d4471..1bd190982 100644
--- a/Emby.Server.Implementations/Localization/Core/bn.json
+++ b/Emby.Server.Implementations/Localization/Core/bn.json
@@ -1,12 +1,12 @@
{
"DeviceOnlineWithName": "{0}-এর সাথে সংযুক্ত হয়েছে",
"DeviceOfflineWithName": "{0}-এর সাথে সংযোগ বিচ্ছিন্ন হয়েছে",
- "Collections": "সংকলন",
+ "Collections": "কলেক্শন",
"ChapterNameValue": "অধ্যায় {0}",
"Channels": "চ্যানেল",
- "CameraImageUploadedFrom": "একটি নতুন ক্যামেরার চিত্র আপলোড করা হয়েছে {0} থেকে",
+ "CameraImageUploadedFrom": "{0} থেকে একটি নতুন ক্যামেরার চিত্র আপলোড করা হয়েছে",
"Books": "বই",
- "AuthenticationSucceededWithUserName": "{0} যাচাই সফল",
+ "AuthenticationSucceededWithUserName": "{0} অনুমোদন সফল",
"Artists": "শিল্পীরা",
"Application": "অ্যাপ্লিকেশন",
"Albums": "অ্যালবামগুলো",
@@ -14,13 +14,13 @@
"HeaderFavoriteArtists": "প্রিয় শিল্পীরা",
"HeaderFavoriteAlbums": "প্রিয় এলবামগুলো",
"HeaderContinueWatching": "দেখতে থাকুন",
- "HeaderCameraUploads": "ক্যামেরার আপলোডগুলো",
- "HeaderAlbumArtists": "এলবামের শিল্পী",
- "Genres": "ঘরানা",
+ "HeaderCameraUploads": "ক্যামেরার আপলোড সমূহ",
+ "HeaderAlbumArtists": "এলবাম শিল্পী",
+ "Genres": "জেনার",
"Folders": "ফোল্ডারগুলো",
- "Favorites": "ফেভারিটগুলো",
+ "Favorites": "পছন্দসমূহ",
"FailedLoginAttemptWithUserName": "{0} লগিন করতে ব্যর্থ হয়েছে",
- "AppDeviceValues": "এপ: {0}, ডিভাইস: {0}",
+ "AppDeviceValues": "অ্যাপ: {0}, ডিভাইস: {0}",
"VersionNumber": "সংস্করণ {0}",
"ValueSpecialEpisodeName": "বিশেষ - {0}",
"ValueHasBeenAddedToLibrary": "আপনার লাইব্রেরিতে {0} যোগ করা হয়েছে",
@@ -74,20 +74,20 @@
"NameInstallFailed": "{0} ইন্সটল ব্যর্থ",
"MusicVideos": "গানের ভিডিও",
"Music": "গান",
- "Movies": "সিনেমা",
+ "Movies": "চলচ্চিত্র",
"MixedContent": "মিশ্র কন্টেন্ট",
- "MessageServerConfigurationUpdated": "সার্ভারের কনফিগারেশন হালনাগাদ করা হয়েছে",
- "HeaderRecordingGroups": "রেকর্ডিং গ্রুপ",
- "MessageNamedServerConfigurationUpdatedWithValue": "সার্ভারের {0} কনফিগারেসন অংশ আপডেট করা হয়েছে",
- "MessageApplicationUpdatedTo": "জেলিফিন সার্ভার {0} তে হালনাগাদ করা হয়েছে",
- "MessageApplicationUpdated": "জেলিফিন সার্ভার হালনাগাদ করা হয়েছে",
- "Latest": "একদম নতুন",
+ "MessageServerConfigurationUpdated": "সার্ভারের কনফিগারেশন আপডেট করা হয়েছে",
+ "HeaderRecordingGroups": "রেকর্ডিং দল",
+ "MessageNamedServerConfigurationUpdatedWithValue": "সার্ভারের {0} কনফিগারেসনের অংশ আপডেট করা হয়েছে",
+ "MessageApplicationUpdatedTo": "জেলিফিন সার্ভার {0} তে আপডেট করা হয়েছে",
+ "MessageApplicationUpdated": "জেলিফিন সার্ভার আপডেট করা হয়েছে",
+ "Latest": "সর্বশেষ",
"LabelRunningTimeValue": "চলার সময়: {0}",
- "LabelIpAddressValue": "আইপি ঠিকানা: {0}",
+ "LabelIpAddressValue": "আইপি এড্রেস: {0}",
"ItemRemovedWithName": "{0} লাইব্রেরি থেকে বাদ দেয়া হয়েছে",
"ItemAddedWithName": "{0} লাইব্রেরিতে যোগ করা হয়েছে",
"Inherit": "থেকে পাওয়া",
- "HomeVideos": "বাসার ভিডিও",
+ "HomeVideos": "হোম ভিডিও",
"HeaderNextUp": "এরপরে আসছে",
"HeaderLiveTV": "লাইভ টিভি",
"HeaderFavoriteSongs": "প্রিয় গানগুলো",
diff --git a/Emby.Server.Implementations/Localization/Core/ta.json b/Emby.Server.Implementations/Localization/Core/ta.json
index f722dd8c0..d6be86da3 100644
--- a/Emby.Server.Implementations/Localization/Core/ta.json
+++ b/Emby.Server.Implementations/Localization/Core/ta.json
@@ -45,7 +45,7 @@
"TvShows": "தொலைக்காட்சித் தொடர்கள்",
"Sync": "ஒத்திசைவு",
"StartupEmbyServerIsLoading": "ஜெல்லிஃபின் சேவையகம் துவங்குகிறது. சிறிது நேரம் கழித்து முயற்சிக்கவும்.",
- "Songs": "பாட்டுகள்",
+ "Songs": "பாடல்கள்",
"Shows": "தொடர்கள்",
"ServerNameNeedsToBeRestarted": "{0} மறுதொடக்கம் செய்யப்பட வேண்டும்",
"ScheduledTaskStartedWithName": "{0} துவங்கியது",
@@ -93,7 +93,25 @@
"Channels": "சேனல்கள்",
"Books": "புத்தகங்கள்",
"AuthenticationSucceededWithUserName": "{0} வெற்றிகரமாக அங்கீகரிக்கப்பட்டது",
- "Artists": "கலைஞர்கள்",
+ "Artists": "கலைஞர்",
"Application": "செயலி",
- "Albums": "ஆல்பங்கள்"
+ "Albums": "ஆல்பங்கள்",
+ "NewVersionIsAvailable": "ஜெல்லிஃபின் சேவையகத்தின் புதிய பதிப்பு பதிவிறக்கத்திற்கு கிடைக்கிறது.",
+ "MessageNamedServerConfigurationUpdatedWithValue": "சேவையக உள்ளமைவு பிரிவு {0 புதுப்பிக்கப்பட்டது",
+ "TaskCleanCacheDescription": "கணினிக்கு இனி தேவைப்படாத தற்காலிக கோப்புகளை நீக்கு.",
+ "UserOfflineFromDevice": "{0} இலிருந்து {1} துண்டிக்கப்பட்டுள்ளது",
+ "SubtitleDownloadFailureFromForItem": "வசன வரிகள் {0 } இலிருந்து {1} க்கு பதிவிறக்கத் தவறிவிட்டன",
+ "TaskDownloadMissingSubtitlesDescription": "மெட்டாடேட்டா உள்ளமைவின் அடிப்படையில் வசன வரிகள் காணாமல் போனதற்கு இணையத்தைத் தேடுகிறது.",
+ "TaskCleanTranscodeDescription": "டிரான்ஸ்கோட் கோப்புகளை ஒரு நாளுக்கு மேல் பழையதாக நீக்குகிறது.",
+ "TaskUpdatePluginsDescription": "தானாகவே புதுப்பிக்க கட்டமைக்கப்பட்ட செருகுநிரல்களுக்கான புதுப்பிப்புகளை பதிவிறக்குகிறது மற்றும் நிறுவுகிறது.",
+ "TaskRefreshPeopleDescription": "உங்கள் மீடியா நூலகத்தில் உள்ள நடிகர்கள் மற்றும் இயக்குனர்களுக்கான மெட்டாடேட்டாவை புதுப்பிக்கும்.",
+ "TaskCleanLogsDescription": "{0} நாட்களுக்கு மேல் இருக்கும் பதிவு கோப்புகளை நீக்கும்.",
+ "TaskCleanLogs": "பதிவு அடைவு சுத்தம் செய்யுங்கள்",
+ "TaskRefreshLibraryDescription": "புதிய கோப்புகளுக்காக உங்கள் மீடியா நூலகத்தை ஸ்கேன் செய்து மீத்தரவை புதுப்பிக்கும்.",
+ "TaskRefreshChapterImagesDescription": "அத்தியாயங்களைக் கொண்ட வீடியோக்களுக்கான சிறு உருவங்களை உருவாக்குகிறது.",
+ "ValueHasBeenAddedToLibrary": "உங்கள் மீடியா நூலகத்தில் {0} சேர்க்கப்பட்டது",
+ "UserOnlineFromDevice": "{1} இருந்து {0} ஆன்லைன்",
+ "HomeVideos": "முகப்பு வீடியோக்கள்",
+ "UserStoppedPlayingItemWithValues": "{2} இல் {1} முடித்துவிட்டது",
+ "UserStartedPlayingItemWithValues": "{0} {2}இல் {1} ஐ இயக்குகிறது"
}
diff --git a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
index 296822981..27024e4e1 100644
--- a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
namespace Emby.Server.Implementations.Serialization
@@ -53,10 +54,11 @@ namespace Emby.Server.Implementations.Serialization
/// The stream.
public void SerializeToStream(object obj, Stream stream)
{
- using (var writer = new XmlTextWriter(stream, null))
+ using (var writer = new StreamWriter(stream, null, IODefaults.StreamWriterBufferSize, true))
+ using (var textWriter = new XmlTextWriter(writer))
{
- writer.Formatting = Formatting.Indented;
- SerializeToWriter(obj, writer);
+ textWriter.Formatting = Formatting.Indented;
+ SerializeToWriter(obj, textWriter);
}
}
@@ -95,7 +97,7 @@ namespace Emby.Server.Implementations.Serialization
/// System.Object.
public object DeserializeFromBytes(Type type, byte[] buffer)
{
- using (var stream = new MemoryStream(buffer))
+ using (var stream = new MemoryStream(buffer, 0, buffer.Length, false, true))
{
return DeserializeFromStream(type, stream);
}
diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs
index ef507f2ed..0100d642b 100644
--- a/Jellyfin.Api/Controllers/DlnaServerController.cs
+++ b/Jellyfin.Api/Controllers/DlnaServerController.cs
@@ -60,8 +60,8 @@ namespace Jellyfin.Api.Controllers
/// Server UUID.
/// Dlna content directory returned.
/// An containing the dlna content directory xml.
- [HttpGet("{serverId}/ContentDirectory/ContentDirectory")]
- [HttpGet("{serverId}/ContentDirectory/ContentDirectory.xml", Name = "GetContentDirectory_2")]
+ [HttpGet("{serverId}/ContentDirectory")]
+ [HttpGet("{serverId}/ContentDirectory.xml", Name = "GetContentDirectory_2")]
[Produces(XMLContentType)]
[ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
@@ -75,8 +75,8 @@ namespace Jellyfin.Api.Controllers
///
/// Server UUID.
/// Dlna media receiver registrar xml.
- [HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar")]
- [HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_2")]
+ [HttpGet("{serverId}/MediaReceiverRegistrar")]
+ [HttpGet("{serverId}/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_2")]
[Produces(XMLContentType)]
[ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
@@ -90,8 +90,8 @@ namespace Jellyfin.Api.Controllers
///
/// Server UUID.
/// Dlna media receiver registrar xml.
- [HttpGet("{serverId}/ConnectionManager/ConnectionManager")]
- [HttpGet("{serverId}/ConnectionManager/ConnectionManager.xml", Name = "GetConnectionManager_2")]
+ [HttpGet("{serverId}/ConnectionManager")]
+ [HttpGet("{serverId}/ConnectionManager.xml", Name = "GetConnectionManager_2")]
[Produces(XMLContentType)]
[ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index 45447ae0c..8f5c6beb3 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -969,7 +969,7 @@ namespace Jellyfin.Api.Controllers
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
var bytes = Convert.FromBase64String(text);
- return new MemoryStream(bytes) { Position = 0 };
+ return new MemoryStream(bytes, 0, bytes.Length, false, true);
}
private ImageInfo? GetImageInfo(BaseItem item, ItemImageInfo info, int? imageIndex)
diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs
index c4a7160cd..bd079bf68 100644
--- a/Jellyfin.Api/Controllers/LiveTvController.cs
+++ b/Jellyfin.Api/Controllers/LiveTvController.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Net.Mime;
using System.Security.Cryptography;
using System.Text;
@@ -15,7 +16,6 @@ using Jellyfin.Api.Models.LiveTvDtos;
using Jellyfin.Data.Enums;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
@@ -39,7 +39,7 @@ namespace Jellyfin.Api.Controllers
{
private readonly ILiveTvManager _liveTvManager;
private readonly IUserManager _userManager;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager;
private readonly IDtoService _dtoService;
private readonly ISessionContext _sessionContext;
@@ -52,7 +52,7 @@ namespace Jellyfin.Api.Controllers
///
/// Instance of the interface.
/// Instance of the interface.
- /// Instance of the interface.
+ /// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
/// Instance of the interface.
@@ -62,7 +62,7 @@ namespace Jellyfin.Api.Controllers
public LiveTvController(
ILiveTvManager liveTvManager,
IUserManager userManager,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager,
IDtoService dtoService,
ISessionContext sessionContext,
@@ -72,7 +72,7 @@ namespace Jellyfin.Api.Controllers
{
_liveTvManager = liveTvManager;
_userManager = userManager;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager;
_dtoService = dtoService;
_sessionContext = sessionContext;
@@ -1069,13 +1069,12 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task GetSchedulesDirectCountries()
{
+ var client = _httpClientFactory.CreateClient();
// https://json.schedulesdirect.org/20141201/available/countries
- var response = await _httpClient.Get(new HttpRequestOptions
- {
- Url = "https://json.schedulesdirect.org/20141201/available/countries",
- BufferContent = false
- }).ConfigureAwait(false);
- return File(response, MediaTypeNames.Application.Json);
+ using var response = await client.GetAsync("https://json.schedulesdirect.org/20141201/available/countries")
+ .ConfigureAwait(false);
+
+ return File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), MediaTypeNames.Application.Json);
}
///
diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs
index baa3d80ac..a203c50b9 100644
--- a/Jellyfin.Api/Controllers/RemoteImageController.cs
+++ b/Jellyfin.Api/Controllers/RemoteImageController.cs
@@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -30,7 +30,7 @@ namespace Jellyfin.Api.Controllers
{
private readonly IProviderManager _providerManager;
private readonly IServerApplicationPaths _applicationPaths;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager;
///
@@ -38,17 +38,17 @@ namespace Jellyfin.Api.Controllers
///
/// Instance of the interface.
/// Instance of the interface.
- /// Instance of the interface.
+ /// Instance of the interface.
/// Instance of the interface.
public RemoteImageController(
IProviderManager providerManager,
IServerApplicationPaths applicationPaths,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager)
{
_providerManager = providerManager;
_applicationPaths = applicationPaths;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager;
}
@@ -244,22 +244,14 @@ namespace Jellyfin.Api.Controllers
/// Task.
private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
{
- using var result = await _httpClient.GetResponse(new HttpRequestOptions
- {
- Url = url,
- BufferContent = false
- }).ConfigureAwait(false);
- var ext = result.ContentType.Split('/').Last();
-
+ var httpClient = _httpClientFactory.CreateClient();
+ using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
+ var ext = response.Content.Headers.ContentType.MediaType.Split('/').Last();
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
- await using (var stream = result.Content)
- {
- await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
- await stream.CopyToAsync(fileStream).ConfigureAwait(false);
- }
-
+ await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
+ await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None)
.ConfigureAwait(false);
diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs
index 8eee51c2c..de9813c58 100644
--- a/Jellyfin.Api/Controllers/VideosController.cs
+++ b/Jellyfin.Api/Controllers/VideosController.cs
@@ -470,8 +470,8 @@ namespace Jellyfin.Api.Controllers
{
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
- using var httpClient = _httpClientFactory.CreateClient();
- return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, httpClient, HttpContext).ConfigureAwait(false);
+ var httpClient = _httpClientFactory.CreateClient();
+ return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, isHeadRequest, this, httpClient).ConfigureAwait(false);
}
if (@static.HasValue && @static.Value && state.InputProtocol != MediaProtocol.File)
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 83d8fac5b..2e2bfea68 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -154,6 +154,7 @@ namespace Jellyfin.Server.Extensions
opts.OutputFormatters.Insert(0, new PascalCaseJsonProfileFormatter());
opts.OutputFormatters.Add(new CssOutputFormatter());
+ opts.OutputFormatters.Add(new XmlOutputFormatter());
})
// Clear app parts to avoid other assemblies being picked up
diff --git a/Jellyfin.Server/Formatters/XmlOutputFormatter.cs b/Jellyfin.Server/Formatters/XmlOutputFormatter.cs
new file mode 100644
index 000000000..58319657d
--- /dev/null
+++ b/Jellyfin.Server/Formatters/XmlOutputFormatter.cs
@@ -0,0 +1,31 @@
+using System.Net.Mime;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Formatters;
+
+namespace Jellyfin.Server.Formatters
+{
+ ///
+ /// Xml output formatter.
+ ///
+ public class XmlOutputFormatter : TextOutputFormatter
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public XmlOutputFormatter()
+ {
+ SupportedMediaTypes.Add(MediaTypeNames.Text.Xml);
+ SupportedMediaTypes.Add("text/xml;charset=UTF-8");
+ SupportedEncodings.Add(Encoding.UTF8);
+ SupportedEncodings.Add(Encoding.Unicode);
+ }
+
+ ///
+ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
+ {
+ return context.HttpContext.Response.WriteAsync(context.Object?.ToString());
+ }
+ }
+}
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 9fd706d36..f6ac4e2a3 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -344,11 +344,24 @@ namespace Jellyfin.Server
}
}
- // Bind to unix socket (only on OSX and Linux)
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ // Bind to unix socket (only on macOS and Linux)
+ if (startupConfig.UseUnixSocket() && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- // TODO: allow configuration of socket path
- var socketPath = $"{appPaths.DataPath}/socket.sock";
+ var socketPath = startupConfig.GetUnixSocketPath();
+ if (string.IsNullOrEmpty(socketPath))
+ {
+ var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
+ if (xdgRuntimeDir == null)
+ {
+ // Fall back to config dir
+ socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, "socket.sock");
+ }
+ else
+ {
+ socketPath = Path.Join(xdgRuntimeDir, "jellyfin-socket");
+ }
+ }
+
// Workaround for https://github.com/aspnet/AspNetCore/issues/14134
if (File.Exists(socketPath))
{
diff --git a/MediaBrowser.Common/Json/Converters/JsonInt64Converter.cs b/MediaBrowser.Common/Json/Converters/JsonInt64Converter.cs
index d18fd95d5..427f1fa7e 100644
--- a/MediaBrowser.Common/Json/Converters/JsonInt64Converter.cs
+++ b/MediaBrowser.Common/Json/Converters/JsonInt64Converter.cs
@@ -8,7 +8,7 @@ using System.Text.Json.Serialization;
namespace MediaBrowser.Common.Json.Converters
{
///
- /// Long to String JSON converter.
+ /// Parse JSON string as long.
/// Javascript does not support 64-bit integers.
///
public class JsonInt64Converter : JsonConverter
@@ -43,14 +43,14 @@ namespace MediaBrowser.Common.Json.Converters
}
///
- /// Write long to JSON string.
+ /// Write long to JSON long.
///
/// .
/// Value to write.
/// Options.
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
{
- writer.WriteStringValue(value.ToString(NumberFormatInfo.InvariantInfo));
+ writer.WriteNumberValue(value);
}
}
}
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index 0dadc283e..988557f42 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Dto
{
@@ -11,20 +10,6 @@ namespace MediaBrowser.Controller.Dto
///
public interface IDtoService
{
- ///
- /// Gets the dto id.
- ///
- /// The item.
- /// System.String.
- string GetDtoId(BaseItem item);
-
- ///
- /// Attaches the primary image aspect ratio.
- ///
- /// The dto.
- /// The item.
- void AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item);
-
///
/// Gets the primary image aspect ratio.
///
@@ -32,15 +17,6 @@ namespace MediaBrowser.Controller.Dto
/// System.Nullable<System.Double>.
double? GetPrimaryImageAspectRatio(BaseItem item);
- ///
- /// Gets the base item dto.
- ///
- /// The item.
- /// The fields.
- /// The user.
- /// The owner.
- BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null);
-
///
/// Gets the base item dto.
///
diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
index c2932cc4c..4c2209b67 100644
--- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
@@ -33,6 +33,16 @@ namespace MediaBrowser.Controller.Extensions
///
public const string PlaylistsAllowDuplicatesKey = "playlists:allowDuplicates";
+ ///
+ /// The key for a setting that indicates whether kestrel should bind to a unix socket.
+ ///
+ public const string BindToUnixSocketKey = "kestrel:socket";
+
+ ///
+ /// The key for the unix socket path.
+ ///
+ public const string UnixSocketPathKey = "kestrel:socketPath";
+
///
/// Gets a value indicating whether the application should host static web content from the .
///
@@ -65,5 +75,21 @@ namespace MediaBrowser.Controller.Extensions
/// True if playlists should allow duplicates, otherwise false.
public static bool DoPlaylistsAllowDuplicates(this IConfiguration configuration)
=> configuration.GetValue(PlaylistsAllowDuplicatesKey);
+
+ ///
+ /// Gets a value indicating whether kestrel should bind to a unix socket from the .
+ ///
+ /// The configuration to read the setting from.
+ /// true if kestrel should bind to a unix socket, otherwise false.
+ public static bool UseUnixSocket(this IConfiguration configuration)
+ => configuration.GetValue(BindToUnixSocketKey);
+
+ ///
+ /// Gets the path for the unix socket from the .
+ ///
+ /// The configuration to read the setting from.
+ /// The unix socket path.
+ public static string GetUnixSocketPath(this IConfiguration configuration)
+ => configuration[UnixSocketPathKey];
}
}
diff --git a/MediaBrowser.Model/Extensions/ListHelper.cs b/MediaBrowser.Model/Extensions/ListHelper.cs
deleted file mode 100644
index b893a3509..000000000
--- a/MediaBrowser.Model/Extensions/ListHelper.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-#nullable disable
-#pragma warning disable CS1591
-
-using System;
-
-namespace MediaBrowser.Model.Extensions
-{
- // TODO: @bond remove
- public static class ListHelper
- {
- public static bool ContainsIgnoreCase(string[] list, string value)
- {
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
- foreach (var item in list)
- {
- if (string.Equals(item, value, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Model/IO/IODefaults.cs b/MediaBrowser.Model/IO/IODefaults.cs
index f392dbcce..d9a1e6777 100644
--- a/MediaBrowser.Model/IO/IODefaults.cs
+++ b/MediaBrowser.Model/IO/IODefaults.cs
@@ -1,3 +1,5 @@
+using System.IO;
+
namespace MediaBrowser.Model.IO
{
///
@@ -14,5 +16,10 @@ namespace MediaBrowser.Model.IO
/// The default file stream buffer size.
///
public const int FileStreamBufferSize = 4096;
+
+ ///
+ /// The default buffer size.
+ ///
+ public const int StreamWriterBufferSize = 1024;
}
}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 32b543fef..26b50784b 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -124,13 +124,16 @@ namespace MediaBrowser.Providers.Manager
var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
// If there are more than one output paths, the stream will need to be seekable
- var memoryStream = new MemoryStream();
- await using (source.ConfigureAwait(false))
+ if (paths.Length > 1 && !source.CanSeek)
{
- await source.CopyToAsync(memoryStream).ConfigureAwait(false);
- }
+ var memoryStream = new MemoryStream();
+ await using (source.ConfigureAwait(false))
+ {
+ await source.CopyToAsync(memoryStream).ConfigureAwait(false);
+ }
- source = memoryStream;
+ source = memoryStream;
+ }
var currentImage = GetCurrentImage(item, type, index);
var currentImageIsLocalFile = currentImage != null && currentImage.IsLocalFile;
@@ -140,20 +143,21 @@ namespace MediaBrowser.Providers.Manager
await using (source.ConfigureAwait(false))
{
- var currentPathIndex = 0;
-
- foreach (var path in paths)
+ for (int i = 0; i < paths.Length; i++)
{
- source.Position = 0;
+ if (i != 0)
+ {
+ source.Position = 0;
+ }
+
string retryPath = null;
if (paths.Length == retryPaths.Length)
{
- retryPath = retryPaths[currentPathIndex];
+ retryPath = retryPaths[i];
}
- var savedPath = await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false);
+ var savedPath = await SaveImageToLocation(source, paths[i], retryPath, cancellationToken).ConfigureAwait(false);
savedPaths.Add(savedPath);
- currentPathIndex++;
}
}
@@ -224,7 +228,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- source.Position = 0;
await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
return retryPath;
}
@@ -253,7 +256,7 @@ namespace MediaBrowser.Providers.Manager
await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
{
- await source.CopyToAsync(fs, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false);
+ await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
}
if (_config.Configuration.SaveMetadataHidden)
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index 3510b90cf..0f7cb3f8f 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Subtitles
CancellationToken cancellationToken)
{
var parts = subtitleId.Split(new[] { '_' }, 2);
- var provider = GetProvider(parts.First());
+ var provider = GetProvider(parts[0]);
var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;