aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs14
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs29
-rw-r--r--Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs335
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs10
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs13
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj6
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs13
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs4
-rw-r--r--Emby.Server.Implementations/Images/BaseFolderImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs75
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/MediaStreamSelector.cs90
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs33
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs33
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs42
-rw-r--r--Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Core/cs.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fa.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/vi.json2
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs8
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs6
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs9
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs17
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs9
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs15
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs9
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs11
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs9
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs9
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs17
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs17
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs17
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs36
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs10
38 files changed, 335 insertions, 584 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index e7efc81d7..82294644b 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -44,7 +44,6 @@ using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV;
-using Emby.Server.Implementations.Udp;
using Emby.Server.Implementations.Updates;
using Jellyfin.Api.Helpers;
using Jellyfin.MediaEncoding.Hls.Playlist;
@@ -104,6 +103,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Prometheus.DotNetRuntime;
+using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
namespace Emby.Server.Implementations
@@ -150,7 +150,7 @@ namespace Emby.Server.Implementations
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
/// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
/// <param name="startupConfig">The <see cref="IConfiguration" /> interface.</param>
- public ApplicationHost(
+ protected ApplicationHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,
@@ -185,6 +185,11 @@ namespace Emby.Server.Implementations
public event EventHandler HasPendingRestartChanged;
/// <summary>
+ /// Gets the value of the PublishedServerUrl setting.
+ /// </summary>
+ private string PublishedServerUrl => _startupConfig[AddressOverrideKey];
+
+ /// <summary>
/// Gets a value indicating whether this instance can self restart.
/// </summary>
public bool CanSelfRestart => _startupOptions.RestartPath != null;
@@ -260,11 +265,6 @@ namespace Emby.Server.Implementations
/// </summary>
public int HttpsPort { get; private set; }
- /// <summary>
- /// Gets the value of the PublishedServerUrl setting.
- /// </summary>
- public string PublishedServerUrl => _startupOptions.PublishedServerUrl ?? _startupConfig[UdpServer.AddressOverrideConfigKey];
-
/// <inheritdoc />
public Version ApplicationVersion { get; }
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index a107e7a52..09429c73f 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Channels
/// <summary>
/// The LiveTV channel manager.
/// </summary>
- public class ChannelManager : IChannelManager
+ public class ChannelManager : IChannelManager, IDisposable
{
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
@@ -52,6 +52,7 @@ namespace Emby.Server.Implementations.Channels
private readonly IMemoryCache _memoryCache;
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
+ private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="ChannelManager"/> class.
@@ -1213,5 +1214,31 @@ namespace Emby.Server.Implementations.Channels
return result;
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and optionally managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _resourcePool?.Dispose();
+ }
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs
index e5dde48d8..cfd08e653 100644
--- a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs
+++ b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Channels
public string Key => "RefreshInternetChannels";
/// <inheritdoc />
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (ChannelManager)_channelManager;
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 1da9b4650..b3b383bfd 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -317,11 +317,6 @@ namespace Emby.Server.Implementations.Data
IImageProcessor imageProcessor)
: base(logger)
{
- if (config == null)
- {
- throw new ArgumentNullException(nameof(config));
- }
-
_config = config;
_appHost = appHost;
_localization = localization;
@@ -334,9 +329,6 @@ namespace Emby.Server.Implementations.Data
}
/// <inheritdoc />
- public string Name => "SQLite";
-
- /// <inheritdoc />
protected override int? CacheSize => 20000;
/// <inheritdoc />
@@ -573,22 +565,6 @@ namespace Emby.Server.Implementations.Data
userDataRepo.Initialize(userManager, WriteLock, WriteConnection);
}
- /// <summary>
- /// Save a standard item in the repo.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <exception cref="ArgumentNullException"><paramref name="item"/> is <c>null</c>.</exception>
- public void SaveItem(BaseItem item, CancellationToken cancellationToken)
- {
- if (item == null)
- {
- throw new ArgumentNullException(nameof(item));
- }
-
- SaveItems(new[] { item }, cancellationToken);
- }
-
public void SaveImages(BaseItem item)
{
if (item == null)
@@ -605,7 +581,7 @@ namespace Emby.Server.Implementations.Data
{
using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
{
- saveImagesStatement.TryBind("@Id", item.Id.ToByteArray());
+ saveImagesStatement.TryBind("@Id", item.Id);
saveImagesStatement.TryBind("@Images", SerializeImages(item.ImageInfos));
saveImagesStatement.MoveNext();
@@ -750,7 +726,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBindNull("@EndDate");
}
- saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(Guid.Empty) ? null : item.ChannelId.ToString("N", CultureInfo.InvariantCulture));
+ saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(default) ? null : item.ChannelId.ToString("N", CultureInfo.InvariantCulture));
if (item is IHasProgramAttributes hasProgramAttributes)
{
@@ -780,7 +756,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBind("@ProductionYear", item.ProductionYear);
var parentId = item.ParentId;
- if (parentId.Equals(Guid.Empty))
+ if (parentId.Equals(default))
{
saveItemStatement.TryBindNull("@ParentId");
}
@@ -975,7 +951,7 @@ namespace Emby.Server.Implementations.Data
{
saveItemStatement.TryBind("@SeasonName", episode.SeasonName);
- var nullableSeasonId = episode.SeasonId == Guid.Empty ? (Guid?)null : episode.SeasonId;
+ var nullableSeasonId = episode.SeasonId.Equals(default) ? (Guid?)null : episode.SeasonId;
saveItemStatement.TryBind("@SeasonId", nullableSeasonId);
}
@@ -987,7 +963,7 @@ namespace Emby.Server.Implementations.Data
if (item is IHasSeries hasSeries)
{
- var nullableSeriesId = hasSeries.SeriesId.Equals(Guid.Empty) ? (Guid?)null : hasSeries.SeriesId;
+ var nullableSeriesId = hasSeries.SeriesId.Equals(default) ? (Guid?)null : hasSeries.SeriesId;
saveItemStatement.TryBind("@SeriesId", nullableSeriesId);
saveItemStatement.TryBind("@SeriesPresentationUniqueKey", hasSeries.SeriesPresentationUniqueKey);
@@ -1060,7 +1036,7 @@ namespace Emby.Server.Implementations.Data
}
Guid ownerId = item.OwnerId;
- if (ownerId == Guid.Empty)
+ if (ownerId.Equals(default))
{
saveItemStatement.TryBindNull("@OwnerId");
}
@@ -1198,13 +1174,15 @@ namespace Emby.Server.Implementations.Data
bldr.Append(Delimiter)
// Replace delimiters with other characters.
// This can be removed when we migrate to a proper DB.
- .Append(hash.Replace('*', '/').Replace('|', '\\'));
+ .Append(hash.Replace(Delimiter, '/').Replace('|', '\\'));
}
}
internal ItemImageInfo ItemImageInfoFromValueString(ReadOnlySpan<char> value)
{
- var nextSegment = value.IndexOf('*');
+ const char Delimiter = '*';
+
+ var nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
return null;
@@ -1212,7 +1190,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> path = value[..nextSegment];
value = value[(nextSegment + 1)..];
- nextSegment = value.IndexOf('*');
+ nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
return null;
@@ -1220,7 +1198,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> dateModified = value[..nextSegment];
value = value[(nextSegment + 1)..];
- nextSegment = value.IndexOf('*');
+ nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
nextSegment = value.Length;
@@ -1257,7 +1235,7 @@ namespace Emby.Server.Implementations.Data
if (nextSegment + 1 < value.Length - 1)
{
value = value[(nextSegment + 1)..];
- nextSegment = value.IndexOf('*');
+ nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1 || nextSegment == value.Length)
{
return image;
@@ -1266,7 +1244,7 @@ namespace Emby.Server.Implementations.Data
ReadOnlySpan<char> widthSpan = value[..nextSegment];
value = value[(nextSegment + 1)..];
- nextSegment = value.IndexOf('*');
+ nextSegment = value.IndexOf(Delimiter);
if (nextSegment == -1)
{
nextSegment = value.Length;
@@ -1292,7 +1270,7 @@ namespace Emby.Server.Implementations.Data
var c = value[i];
blurHashSpan[i] = c switch
{
- '/' => '*',
+ '/' => Delimiter,
'\\' => '|',
_ => c
};
@@ -1314,7 +1292,7 @@ namespace Emby.Server.Implementations.Data
/// <exception cref="ArgumentException"><paramr name="id"/> is <seealso cref="Guid.Empty"/>.</exception>
public BaseItem RetrieveItem(Guid id)
{
- if (id == Guid.Empty)
+ if (id.Equals(default))
{
throw new ArgumentException("Guid can't be empty", nameof(id));
}
@@ -2086,7 +2064,7 @@ namespace Emby.Server.Implementations.Data
{
CheckDisposed();
- if (id.Equals(Guid.Empty))
+ if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -2492,12 +2470,12 @@ namespace Emby.Server.Implementations.Data
searchTerm = GetCleanValue(searchTerm);
var commandText = statement.SQL;
- if (commandText.IndexOf("@SearchTermStartsWith", StringComparison.OrdinalIgnoreCase) != -1)
+ if (commandText.Contains("@SearchTermStartsWith", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SearchTermStartsWith", searchTerm + "%");
}
- if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1)
+ if (commandText.Contains("@SearchTermContains", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SearchTermContains", "%" + searchTerm + "%");
}
@@ -2514,17 +2492,17 @@ namespace Emby.Server.Implementations.Data
var commandText = statement.SQL;
- if (commandText.IndexOf("@ItemOfficialRating", StringComparison.OrdinalIgnoreCase) != -1)
+ if (commandText.Contains("@ItemOfficialRating", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@ItemOfficialRating", item.OfficialRating);
}
- if (commandText.IndexOf("@ItemProductionYear", StringComparison.OrdinalIgnoreCase) != -1)
+ if (commandText.Contains("@ItemProductionYear", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@ItemProductionYear", item.ProductionYear ?? 0);
}
- if (commandText.IndexOf("@SimilarItemId", StringComparison.OrdinalIgnoreCase) != -1)
+ if (commandText.Contains("@SimilarItemId", StringComparison.OrdinalIgnoreCase))
{
statement.TryBind("@SimilarItemId", item.Id);
}
@@ -2758,12 +2736,12 @@ namespace Emby.Server.Implementations.Data
foreach (var providerId in newItem.ProviderIds)
{
- if (providerId.Key == MetadataProvider.TmdbCollection.ToString())
+ if (string.Equals(providerId.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.Ordinal))
{
continue;
}
- if (item.GetProviderId(providerId.Key) == providerId.Value)
+ if (string.Equals(item.GetProviderId(providerId.Key), providerId.Value, StringComparison.Ordinal))
{
if (newItem.SourceType == SourceType.Library)
{
@@ -3185,220 +3163,6 @@ namespace Emby.Server.Implementations.Data
return list;
}
- public List<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query)
- {
- if (query == null)
- {
- throw new ArgumentNullException(nameof(query));
- }
-
- CheckDisposed();
-
- var now = DateTime.UtcNow;
-
- var columns = new List<string> { "guid", "path" };
- SetFinalColumnsToSelect(query, columns);
- var commandText = "select " + string.Join(',', columns) + FromText;
-
- var whereClauses = GetWhereClauses(query, null);
- if (whereClauses.Count != 0)
- {
- commandText += " where " + string.Join(" AND ", whereClauses);
- }
-
- commandText += GetGroupBy(query)
- + GetOrderByText(query);
-
- if (query.Limit.HasValue || query.StartIndex.HasValue)
- {
- var offset = query.StartIndex ?? 0;
-
- if (query.Limit.HasValue || offset > 0)
- {
- commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
- }
-
- if (offset > 0)
- {
- commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
- }
- }
-
- var list = new List<Tuple<Guid, string>>();
- using (var connection = GetConnection(true))
- {
- using (var statement = PrepareStatement(connection, commandText))
- {
- if (EnableJoinUserData(query))
- {
- statement.TryBind("@UserId", query.User.InternalId);
- }
-
- // Running this again will bind the params
- GetWhereClauses(query, statement);
-
- foreach (var row in statement.ExecuteQuery())
- {
- var id = row.GetGuid(0);
-
- row.TryGetString(1, out var path);
-
- list.Add(new Tuple<Guid, string>(id, path));
- }
- }
- }
-
- LogQueryTime("GetItemIdsWithPath", commandText, now);
-
- return list;
- }
-
- public QueryResult<Guid> GetItemIds(InternalItemsQuery query)
- {
- if (query == null)
- {
- throw new ArgumentNullException(nameof(query));
- }
-
- CheckDisposed();
-
- if (!query.EnableTotalRecordCount || (!query.Limit.HasValue && (query.StartIndex ?? 0) == 0))
- {
- var returnList = GetItemIdsList(query);
- return new QueryResult<Guid>(
- query.StartIndex,
- returnList.Count,
- returnList);
- }
-
- var now = DateTime.UtcNow;
-
- var columns = new List<string> { "guid" };
- SetFinalColumnsToSelect(query, columns);
- var commandText = "select "
- + string.Join(',', columns)
- + FromText
- + GetJoinUserDataText(query);
-
- var whereClauses = GetWhereClauses(query, null);
-
- var whereText = whereClauses.Count == 0 ?
- string.Empty :
- " where " + string.Join(" AND ", whereClauses);
-
- commandText += whereText
- + GetGroupBy(query)
- + GetOrderByText(query);
-
- if (query.Limit.HasValue || query.StartIndex.HasValue)
- {
- var offset = query.StartIndex ?? 0;
-
- if (query.Limit.HasValue || offset > 0)
- {
- commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture);
- }
-
- if (offset > 0)
- {
- commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture);
- }
- }
-
- var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
-
- var statementTexts = new List<string>();
- if (!isReturningZeroItems)
- {
- statementTexts.Add(commandText);
- }
-
- if (query.EnableTotalRecordCount)
- {
- commandText = string.Empty;
-
- List<string> columnsToSelect;
- if (EnableGroupByPresentationUniqueKey(query))
- {
- columnsToSelect = new List<string> { "count (distinct PresentationUniqueKey)" };
- }
- else if (query.GroupBySeriesPresentationUniqueKey)
- {
- columnsToSelect = new List<string> { "count (distinct SeriesPresentationUniqueKey)" };
- }
- else
- {
- columnsToSelect = new List<string> { "count (guid)" };
- }
-
- SetFinalColumnsToSelect(query, columnsToSelect);
- commandText += " select " + string.Join(',', columnsToSelect) + FromText;
-
- commandText += GetJoinUserDataText(query)
- + whereText;
- statementTexts.Add(commandText);
- }
-
- var list = new List<Guid>();
- var result = new QueryResult<Guid>();
- using (var connection = GetConnection(true))
- {
- connection.RunInTransaction(
- db =>
- {
- var statements = PrepareAll(db, statementTexts);
-
- if (!isReturningZeroItems)
- {
- using (var statement = statements[0])
- {
- if (EnableJoinUserData(query))
- {
- statement.TryBind("@UserId", query.User.InternalId);
- }
-
- BindSimilarParams(query, statement);
- BindSearchParams(query, statement);
-
- // Running this again will bind the params
- GetWhereClauses(query, statement);
-
- foreach (var row in statement.ExecuteQuery())
- {
- list.Add(row[0].ReadGuidFromBlob());
- }
- }
- }
-
- if (query.EnableTotalRecordCount)
- {
- using (var statement = statements[statements.Length - 1])
- {
- if (EnableJoinUserData(query))
- {
- statement.TryBind("@UserId", query.User.InternalId);
- }
-
- BindSimilarParams(query, statement);
- BindSearchParams(query, statement);
-
- // Running this again will bind the params
- GetWhereClauses(query, statement);
-
- result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
- }
- }
- },
- ReadTransactionMode);
- }
-
- LogQueryTime("GetItemIds", commandText, now);
-
- result.StartIndex = query.StartIndex ?? 0;
- result.Items = list;
- return result;
- }
-
private bool IsAlphaNumeric(string str)
{
if (string.IsNullOrWhiteSpace(str))
@@ -3665,7 +3429,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add($"ChannelId in ({inClause})");
}
- if (!query.ParentId.Equals(Guid.Empty))
+ if (!query.ParentId.Equals(default))
{
whereClauses.Add("ParentId=@ParentId");
statement?.TryBind("@ParentId", query.ParentId);
@@ -4025,7 +3789,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToByteArray());
+ statement.TryBind(paramName, artistId);
}
index++;
@@ -4046,7 +3810,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToByteArray());
+ statement.TryBind(paramName, artistId);
}
index++;
@@ -4067,7 +3831,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToByteArray());
+ statement.TryBind(paramName, artistId);
}
index++;
@@ -4088,7 +3852,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
if (statement != null)
{
- statement.TryBind(paramName, albumId.ToByteArray());
+ statement.TryBind(paramName, albumId);
}
index++;
@@ -4109,7 +3873,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
if (statement != null)
{
- statement.TryBind(paramName, artistId.ToByteArray());
+ statement.TryBind(paramName, artistId);
}
index++;
@@ -4130,7 +3894,7 @@ namespace Emby.Server.Implementations.Data
clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
if (statement != null)
{
- statement.TryBind(paramName, genreId.ToByteArray());
+ statement.TryBind(paramName, genreId);
}
index++;
@@ -4209,7 +3973,7 @@ namespace Emby.Server.Implementations.Data
if (statement != null)
{
- statement.TryBind(paramName, studioId.ToByteArray());
+ statement.TryBind(paramName, studioId);
}
index++;
@@ -4494,7 +4258,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var pair in query.ExcludeProviderIds)
{
- if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(pair.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -4524,7 +4288,7 @@ namespace Emby.Server.Implementations.Data
var index = 0;
foreach (var pair in query.HasAnyProviderId)
{
- if (string.Equals(pair.Key, MetadataProvider.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(pair.Key, nameof(MetadataProvider.TmdbCollection), StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -4942,7 +4706,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
public void DeleteItem(Guid id)
{
- if (id == Guid.Empty)
+ if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -4954,7 +4718,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction(
db =>
{
- var idBlob = id.ToByteArray();
+ Span<byte> idBlob = stackalloc byte[16];
+ id.TryWriteBytes(idBlob);
// Delete people
ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob);
@@ -5003,7 +4768,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
if (whereClauses.Count != 0)
{
- commandText.Append(" where ").Append(string.Join(" AND ", whereClauses));
+ commandText.Append(" where ").AppendJoin(" AND ", whereClauses);
}
commandText.Append(" order by ListOrder");
@@ -5089,16 +4854,16 @@ AND Type = @InternalPersonType)");
statement?.TryBind("@InternalPersonType", typeof(Person).FullName);
}
- if (!query.ItemId.Equals(Guid.Empty))
+ if (!query.ItemId.Equals(default))
{
whereClauses.Add("ItemId=@ItemId");
- statement?.TryBind("@ItemId", query.ItemId.ToByteArray());
+ statement?.TryBind("@ItemId", query.ItemId);
}
- if (!query.AppearsInItemId.Equals(Guid.Empty))
+ if (!query.AppearsInItemId.Equals(default))
{
whereClauses.Add("p.Name in (Select Name from People where ItemId=@AppearsInItemId)");
- statement?.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
+ statement?.TryBind("@AppearsInItemId", query.AppearsInItemId);
}
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
@@ -5151,7 +4916,7 @@ AND Type = @InternalPersonType)");
private void UpdateAncestors(Guid itemId, List<Guid> ancestorIds, IDatabaseConnection db, IStatement deleteAncestorsStatement)
{
- if (itemId.Equals(Guid.Empty))
+ if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5683,7 +5448,7 @@ AND Type = @InternalPersonType)");
private void UpdateItemValues(Guid itemId, List<(int MagicNumber, string Value)> values, IDatabaseConnection db)
{
- if (itemId.Equals(Guid.Empty))
+ if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5759,7 +5524,7 @@ AND Type = @InternalPersonType)");
public void UpdatePeople(Guid itemId, List<PersonInfo> people)
{
- if (itemId.Equals(Guid.Empty))
+ if (itemId.Equals(default))
{
throw new ArgumentNullException(nameof(itemId));
}
@@ -5892,7 +5657,7 @@ AND Type = @InternalPersonType)");
using (var statement = PrepareStatement(connection, cmdText))
{
- statement.TryBind("@ItemId", query.ItemId.ToByteArray());
+ statement.TryBind("@ItemId", query.ItemId);
if (query.Type.HasValue)
{
@@ -5914,11 +5679,11 @@ AND Type = @InternalPersonType)");
}
}
- public void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
+ public void SaveMediaStreams(Guid id, IReadOnlyList<MediaStream> streams, CancellationToken cancellationToken)
{
CheckDisposed();
- if (id == Guid.Empty)
+ if (id.Equals(default))
{
throw new ArgumentNullException(nameof(id));
}
@@ -5946,7 +5711,7 @@ AND Type = @InternalPersonType)");
}
}
- private void InsertMediaStreams(byte[] idBlob, List<MediaStream> streams, IDatabaseConnection db)
+ private void InsertMediaStreams(byte[] idBlob, IReadOnlyList<MediaStream> streams, IDatabaseConnection db)
{
const int Limit = 10;
var startIndex = 0;
@@ -6254,7 +6019,7 @@ AND Type = @InternalPersonType)");
CancellationToken cancellationToken)
{
CheckDisposed();
- if (id == Guid.Empty)
+ if (id.Equals(default))
{
throw new ArgumentException("Guid can't be empty.", nameof(id));
}
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index 80b8f9ebf..ba86dc156 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -26,9 +26,6 @@ namespace Emby.Server.Implementations.Data
DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
}
- /// <inheritdoc />
- public string Name => "SQLite";
-
/// <summary>
/// Opens the connection to the database.
/// </summary>
@@ -102,7 +99,7 @@ namespace Emby.Server.Implementations.Data
continue;
}
- statement.TryBind("@UserId", user.Id.ToByteArray());
+ statement.TryBind("@UserId", user.Id);
statement.TryBind("@InternalUserId", user.InternalId);
statement.MoveNext();
@@ -390,6 +387,7 @@ namespace Emby.Server.Implementations.Data
return userData;
}
+#pragma warning disable CA2215
/// <inheritdoc/>
/// <remarks>
/// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
@@ -398,6 +396,10 @@ namespace Emby.Server.Implementations.Data
/// </remarks>
protected override void Dispose(bool dispose)
{
+ // The write lock and connection for the item repository are shared with the user data repository
+ // since they point to the same database. The item repo has responsibility for disposing these two objects,
+ // so the user data repo should not attempt to dispose them as well
}
+#pragma warning restore CA2215
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index f5ca006dd..2b2190b16 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -21,7 +21,6 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -738,8 +737,7 @@ namespace Emby.Server.Implementations.Dto
dto.Tags = item.Tags;
}
- var hasAspectRatio = item as IHasAspectRatio;
- if (hasAspectRatio != null)
+ if (item is IHasAspectRatio hasAspectRatio)
{
dto.AspectRatio = hasAspectRatio.AspectRatio;
}
@@ -889,15 +887,13 @@ namespace Emby.Server.Implementations.Dto
dto.CommunityRating = item.CommunityRating;
}
- var supportsPlaceHolders = item as ISupportsPlaceHolders;
- if (supportsPlaceHolders != null && supportsPlaceHolders.IsPlaceHolder)
+ if (item is ISupportsPlaceHolders supportsPlaceHolders && supportsPlaceHolders.IsPlaceHolder)
{
dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder;
}
// Add audio info
- var audio = item as Audio;
- if (audio != null)
+ if (item is Audio audio)
{
dto.Album = audio.Album;
if (audio.ExtraType.HasValue)
@@ -970,8 +966,7 @@ namespace Emby.Server.Implementations.Dto
}).Where(i => i != null).ToArray();
}
- var hasAlbumArtist = item as IHasAlbumArtist;
- if (hasAlbumArtist != null)
+ if (item is IHasAlbumArtist hasAlbumArtist)
{
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index d59db6aa7..a5cc125ec 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -26,12 +26,12 @@
<PackageReference Include="DiscUtils.Udf" Version="0.16.13" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.6.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
- <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.1" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.2" />
<PackageReference Include="Mono.Nat" Version="3.0.2" />
- <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.2" />
+ <PackageReference Include="prometheus-net.DotNetRuntime" Version="4.2.3" />
<PackageReference Include="sharpcompress" Version="0.30.1" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="3.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index feaccf9fa..34fdfbe8d 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -3,6 +3,8 @@ using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
+using Jellyfin.Networking.Configuration;
+using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
using Microsoft.Extensions.Configuration;
@@ -26,6 +28,7 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ILogger<UdpServerEntryPoint> _logger;
private readonly IServerApplicationHost _appHost;
private readonly IConfiguration _config;
+ private readonly IConfigurationManager _configurationManager;
/// <summary>
/// The UDP server.
@@ -40,14 +43,17 @@ namespace Emby.Server.Implementations.EntryPoints
/// <param name="logger">Instance of the <see cref="ILogger{UdpServerEntryPoint}"/> interface.</param>
/// <param name="appHost">Instance of the <see cref="IServerApplicationHost"/> interface.</param>
/// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param>
+ /// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param>
public UdpServerEntryPoint(
ILogger<UdpServerEntryPoint> logger,
IServerApplicationHost appHost,
- IConfiguration configuration)
+ IConfiguration configuration,
+ IConfigurationManager configurationManager)
{
_logger = logger;
_appHost = appHost;
_config = configuration;
+ _configurationManager = configurationManager;
}
/// <inheritdoc />
@@ -55,6 +61,11 @@ namespace Emby.Server.Implementations.EntryPoints
{
CheckDisposed();
+ if (_configurationManager.GetNetworkConfiguration().AutoDiscovery)
+ {
+ return Task.CompletedTask;
+ }
+
try
{
_udpServer = new UdpServer(_logger, _appHost, _config, PortNumber);
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 5c86dbbb7..4f8a52f41 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -581,7 +581,7 @@ namespace Emby.Server.Implementations.IO
}
/// <inheritdoc />
- public virtual List<FileSystemMetadata> GetDrives()
+ public virtual IEnumerable<FileSystemMetadata> GetDrives()
{
// check for ready state to avoid waiting for drives to timeout
// some drives on linux have no actual size or are used for other purposes
@@ -595,7 +595,7 @@ namespace Emby.Server.Implementations.IO
Name = d.Name,
FullName = d.RootDirectory.FullName,
IsDirectory = true
- }).ToList();
+ });
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs
index 1c69056d2..6fc7f1ac3 100644
--- a/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseFolderImageProvider.cs
@@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Images
{
private readonly ILibraryManager _libraryManager;
- public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
+ protected BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
: base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
_libraryManager = libraryManager;
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 064fd2372..e3be5627f 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -45,7 +45,6 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
-using MediaBrowser.Providers.MediaInfo;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
@@ -680,9 +679,7 @@ namespace Emby.Server.Implementations.Library
if (result?.Items.Count > 0)
{
- var items = new List<BaseItem>();
- items.AddRange(result.Items);
-
+ var items = result.Items;
foreach (var item in items)
{
ResolverHelper.SetInitialItemValues(item, parent, this, directoryService);
@@ -1007,14 +1004,8 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
- /// <summary>
- /// Validate and refresh the People sub-set of the IBN.
- /// The items are stored in the db but not loaded into memory until actually requested by an operation.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
// Ensure the location is available.
Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);
@@ -1037,15 +1028,6 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Queues the library scan.
- /// </summary>
- public void QueueLibraryScan()
- {
- // Just run the scheduled task so that the user can see it
- _taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
- }
-
- /// <summary>
/// Validates the media library internal.
/// </summary>
/// <param name="progress">The progress.</param>
@@ -1651,27 +1633,6 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Gets all intro files.
- /// </summary>
- /// <returns>IEnumerable{System.String}.</returns>
- public IEnumerable<string> GetAllIntroFiles()
- {
- return IntroProviders.SelectMany(i =>
- {
- try
- {
- return i.GetAllIntroFiles().ToList();
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting intro files");
-
- return new List<string>();
- }
- });
- }
-
- /// <summary>
/// Resolves the intro.
/// </summary>
/// <param name="info">The info.</param>
@@ -2469,24 +2430,6 @@ namespace Emby.Server.Implementations.Library
return item;
}
- public void AddExternalSubtitleStreams(
- List<MediaStream> streams,
- string videoPath,
- string[] files)
- {
- new SubtitleResolver(BaseItem.LocalizationManager).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
- }
-
- public BaseItem GetParentItem(string parentId, Guid? userId)
- {
- if (string.IsNullOrEmpty(parentId))
- {
- return GetParentItem((Guid?)null, userId);
- }
-
- return GetParentItem(new Guid(parentId), userId);
- }
-
public BaseItem GetParentItem(Guid? parentId, Guid? userId)
{
if (parentId.HasValue)
@@ -2494,7 +2437,7 @@ namespace Emby.Server.Implementations.Library
return GetItemById(parentId.Value);
}
- if (userId.HasValue && userId != Guid.Empty)
+ if (userId.HasValue && !userId.Equals(default))
{
return GetUserRootFolder();
}
@@ -2784,16 +2727,6 @@ namespace Emby.Server.Implementations.Library
return path;
}
- public string SubstitutePath(string path, string from, string to)
- {
- if (path.TryReplaceSubPath(from, to, out var newPath))
- {
- return newPath;
- }
-
- return path;
- }
-
public List<PersonInfo> GetPeople(InternalPeopleQuery query)
{
return _itemRepository.GetPeople(query);
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index a414e7e16..eb95977ef 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -344,7 +344,7 @@ namespace Emby.Server.Implementations.Library
return sources;
}
- private string[] NormalizeLanguage(string language)
+ private IReadOnlyList<string> NormalizeLanguage(string language)
{
if (string.IsNullOrEmpty(language))
{
diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
index da0c89c13..c5abb9a0a 100644
--- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs
+++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
#pragma warning disable CS1591
using System;
@@ -13,10 +11,9 @@ namespace Emby.Server.Implementations.Library
{
public static class MediaStreamSelector
{
- public static int? GetDefaultAudioStreamIndex(List<MediaStream> streams, string[] preferredLanguages, bool preferDefaultTrack)
+ public static int? GetDefaultAudioStreamIndex(IReadOnlyList<MediaStream> streams, IReadOnlyList<string> preferredLanguages, bool preferDefaultTrack)
{
- streams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages)
- .ToList();
+ var sortedStreams = GetSortedStreams(streams, MediaStreamType.Audio, preferredLanguages);
if (preferDefaultTrack)
{
@@ -28,24 +25,15 @@ namespace Emby.Server.Implementations.Library
}
}
- var stream = streams.FirstOrDefault();
-
- if (stream != null)
- {
- return stream.Index;
- }
-
- return null;
+ return sortedStreams.FirstOrDefault()?.Index;
}
public static int? GetDefaultSubtitleStreamIndex(
IEnumerable<MediaStream> streams,
- string[] preferredLanguages,
+ IReadOnlyList<string> preferredLanguages,
SubtitlePlaybackMode mode,
string audioTrackLanguage)
{
- MediaStream stream = null;
-
if (mode == SubtitlePlaybackMode.None)
{
return null;
@@ -59,6 +47,7 @@ namespace Emby.Server.Implementations.Library
.ThenByDescending(x => x.IsDefault)
.ToList();
+ MediaStream? stream = null;
if (mode == SubtitlePlaybackMode.Default)
{
// Prefer embedded metadata over smart logic
@@ -95,26 +84,27 @@ namespace Emby.Server.Implementations.Library
return stream?.Index;
}
- private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, string[] languagePreferences)
+ private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, IReadOnlyList<string> languagePreferences)
{
// Give some preference to external text subs for better performance
- return streams.Where(i => i.Type == type)
+ return streams
+ .Where(i => i.Type == type)
.OrderBy(i =>
- {
- var index = FindIndex(languagePreferences, i.Language);
-
- return index == -1 ? 100 : index;
- })
- .ThenBy(i => GetBooleanOrderBy(i.IsDefault))
- .ThenBy(i => GetBooleanOrderBy(i.SupportsExternalStream))
- .ThenBy(i => GetBooleanOrderBy(i.IsTextSubtitleStream))
- .ThenBy(i => GetBooleanOrderBy(i.IsExternal))
- .ThenBy(i => i.Index);
+ {
+ var index = languagePreferences.FindIndex(x => string.Equals(x, i.Language, StringComparison.OrdinalIgnoreCase));
+
+ return index == -1 ? 100 : index;
+ })
+ .ThenBy(i => GetBooleanOrderBy(i.IsDefault))
+ .ThenBy(i => GetBooleanOrderBy(i.SupportsExternalStream))
+ .ThenBy(i => GetBooleanOrderBy(i.IsTextSubtitleStream))
+ .ThenBy(i => GetBooleanOrderBy(i.IsExternal))
+ .ThenBy(i => i.Index);
}
public static void SetSubtitleStreamScores(
- List<MediaStream> streams,
- string[] preferredLanguages,
+ IReadOnlyList<MediaStream> streams,
+ IReadOnlyList<string> preferredLanguages,
SubtitlePlaybackMode mode,
string audioTrackLanguage)
{
@@ -123,15 +113,14 @@ namespace Emby.Server.Implementations.Library
return;
}
- streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages)
- .ToList();
+ var sortedStreams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages);
var filteredStreams = new List<MediaStream>();
if (mode == SubtitlePlaybackMode.Default)
{
// Prefer embedded metadata over smart logic
- filteredStreams = streams.Where(s => s.IsForced || s.IsDefault)
+ filteredStreams = sortedStreams.Where(s => s.IsForced || s.IsDefault)
.ToList();
}
else if (mode == SubtitlePlaybackMode.Smart)
@@ -139,54 +128,37 @@ namespace Emby.Server.Implementations.Library
// Prefer smart logic over embedded metadata
if (!preferredLanguages.Contains(audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
{
- filteredStreams = streams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase))
+ filteredStreams = sortedStreams.Where(s => !s.IsForced && preferredLanguages.Contains(s.Language, StringComparison.OrdinalIgnoreCase))
.ToList();
}
}
else if (mode == SubtitlePlaybackMode.Always)
{
// always load the most suitable full subtitles
- filteredStreams = streams.Where(s => !s.IsForced)
- .ToList();
+ filteredStreams = sortedStreams.Where(s => !s.IsForced).ToList();
}
else if (mode == SubtitlePlaybackMode.OnlyForced)
{
// always load the most suitable full subtitles
- filteredStreams = streams.Where(s => s.IsForced).ToList();
+ filteredStreams = sortedStreams.Where(s => s.IsForced).ToList();
}
// load forced subs if we have found no suitable full subtitles
- if (filteredStreams.Count == 0)
- {
- filteredStreams = streams
- .Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
+ var iterStreams = filteredStreams.Count == 0
+ ? sortedStreams.Where(s => s.IsForced && string.Equals(s.Language, audioTrackLanguage, StringComparison.OrdinalIgnoreCase))
+ : filteredStreams;
- foreach (var stream in filteredStreams)
+ foreach (var stream in iterStreams)
{
stream.Score = GetSubtitleScore(stream, preferredLanguages);
}
}
- private static int FindIndex(string[] list, string value)
- {
- for (var i = 0; i < list.Length; i++)
- {
- if (string.Equals(list[i], value, StringComparison.OrdinalIgnoreCase))
- {
- return i;
- }
- }
-
- return -1;
- }
-
- private static int GetSubtitleScore(MediaStream stream, string[] languagePreferences)
+ private static int GetSubtitleScore(MediaStream stream, IReadOnlyList<string> languagePreferences)
{
var values = new List<int>();
- var index = FindIndex(languagePreferences, stream.Language);
+ var index = languagePreferences.FindIndex(x => string.Equals(x, stream.Language, StringComparison.OrdinalIgnoreCase));
values.Add(index == -1 ? 0 : 100 - index);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index f1d4b6097..582e61d79 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -24,7 +24,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
- public class EncodedRecorder : IRecorder
+ public class EncodedRecorder : IRecorder, IDisposable
{
private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder;
@@ -36,6 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private Stream _logFileStream;
private string _targetPath;
private Process _process;
+ private bool _disposed = false;
public EncodedRecorder(
ILogger logger,
@@ -323,5 +324,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogError(ex, "Error reading ffmpeg recording log");
}
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and optionally managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _logFileStream?.Dispose();
+ _process?.Dispose();
+ }
+
+ _logFileStream = null;
+ _process = null;
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index a8440102d..ffa0d9b6a 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -28,7 +28,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.Listings
{
- public class SchedulesDirect : IListingsProvider
+ public class SchedulesDirect : IListingsProvider, IDisposable
{
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
@@ -39,6 +39,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private DateTime _lastErrorResponse;
+ private bool _disposed = false;
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
@@ -58,8 +59,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var dates = new List<string>();
- var start = new List<DateTime> { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
- var end = new List<DateTime> { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
+ var start = new[] { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
+ var end = new[] { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
while (start <= end)
{
@@ -822,5 +823,31 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return list;
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and optionally managed resources.
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _tokenSemaphore?.Dispose();
+ }
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 6a9a3077c..71a29e3cb 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.LiveTv
/// <summary>
/// Class LiveTvManager.
/// </summary>
- public class LiveTvManager : ILiveTvManager, IDisposable
+ public class LiveTvManager : ILiveTvManager
{
private const int MaxGuideDays = 14;
private const string ExternalServiceTag = "ExternalServiceId";
@@ -63,8 +63,6 @@ namespace Emby.Server.Implementations.LiveTv
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
- private bool _disposed = false;
-
public LiveTvManager(
IServerConfigurationManager config,
ILogger<LiveTvManager> logger,
@@ -312,7 +310,7 @@ namespace Emby.Server.Implementations.LiveTv
{
if (isVideo)
{
- mediaSource.MediaStreams.AddRange(new List<MediaStream>
+ mediaSource.MediaStreams = new MediaStream[]
{
new MediaStream
{
@@ -329,11 +327,11 @@ namespace Emby.Server.Implementations.LiveTv
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
- });
+ };
}
else
{
- mediaSource.MediaStreams.AddRange(new List<MediaStream>
+ mediaSource.MediaStreams = new MediaStream[]
{
new MediaStream
{
@@ -341,7 +339,7 @@ namespace Emby.Server.Implementations.LiveTv
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
- });
+ };
}
}
@@ -2092,36 +2090,6 @@ namespace Emby.Server.Implementations.LiveTv
};
}
- /// <inheritdoc />
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (_disposed)
- {
- return;
- }
-
- if (dispose)
- {
- // TODO: Dispose stuff
- }
-
- _services = null;
- _listingProviders = null;
- _tunerHosts = null;
-
- _disposed = true;
- }
-
private LiveTvServiceInfo[] GetServiceInfos()
{
return Services.Select(GetServiceInfo).ToArray();
diff --git a/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs
index 15df0dcf1..72bbdd14a 100644
--- a/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs
+++ b/Emby.Server.Implementations/LiveTv/RefreshGuideScheduledTask.cs
@@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.LiveTv
public string Key => "RefreshGuide";
/// <inheritdoc />
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (LiveTvManager)_liveTvManager;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 532790019..e0eaa8e58 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -446,7 +446,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
Path = url,
Protocol = MediaProtocol.Udp,
- MediaStreams = new List<MediaStream>
+ MediaStreams = new MediaStream[]
{
new MediaStream
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index dd83f9a53..2a468e14d 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -170,7 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
Path = path,
Protocol = protocol,
- MediaStreams = new List<MediaStream>
+ MediaStreams = new MediaStream[]
{
new MediaStream
{
diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json
index 65a31e676..7ee8d1040 100644
--- a/Emby.Server.Implementations/Localization/Core/cs.json
+++ b/Emby.Server.Implementations/Localization/Core/cs.json
@@ -77,7 +77,7 @@
"SubtitleDownloadFailureFromForItem": "Stažení titulků pro {1} z {0} selhalo",
"Sync": "Synchronizace",
"System": "Systém",
- "TvShows": "TV seriály",
+ "TvShows": "Seriály",
"User": "Uživatel",
"UserCreatedWithName": "Uživatel {0} byl vytvořen",
"UserDeletedWithName": "Uživatel {0} byl smazán",
diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json
index 6960ff007..8e8eef867 100644
--- a/Emby.Server.Implementations/Localization/Core/fa.json
+++ b/Emby.Server.Implementations/Localization/Core/fa.json
@@ -119,5 +119,6 @@
"TaskCleanActivityLogDescription": "ورودی‌های قدیمی‌تر از سن تنظیم شده در سیاهه فعالیت را حذف می‌کند.",
"TaskCleanActivityLog": "پاکسازی سیاهه فعالیت",
"Undefined": "تعریف نشده",
- "TaskOptimizeDatabase": "بهینه سازی پایگاه داده"
+ "TaskOptimizeDatabase": "بهینه سازی پایگاه داده",
+ "TaskOptimizeDatabaseDescription": "فشرده سازی پایگاه داده و باز کردن فضای آزاد.اجرای این گزینه بعد از اسکن کردن کتابخانه یا تغییرات دیگر که روی پایگاه داده تأثیر میگذارند میتواند کارایی را بهبود ببخشد."
}
diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json
index d80f1760d..d0e08d8ee 100644
--- a/Emby.Server.Implementations/Localization/Core/vi.json
+++ b/Emby.Server.Implementations/Localization/Core/vi.json
@@ -13,7 +13,7 @@
"Songs": "Bài Hát",
"Sync": "Đồng Bộ",
"ValueSpecialEpisodeName": "Đặc Biệt - {0}",
- "Albums": "",
+ "Albums": "Album",
"Artists": "Ca Sĩ",
"TaskDownloadMissingSubtitlesDescription": "Tìm kiếm phụ đề bị thiếu trên Internet dựa trên cấu hình dữ liệu mô tả.",
"TaskDownloadMissingSubtitles": "Tải Xuống Phụ Đề Bị Thiếu",
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index dbd70342a..281dbb00b 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -147,13 +147,7 @@ namespace Emby.Server.Implementations.Localization
threeletterNames = new[] { parts[0], parts[1] };
}
- list.Add(new CultureDto
- {
- DisplayName = name,
- Name = name,
- ThreeLetterISOLanguageNames = threeletterNames,
- TwoLetterISOLanguageName = twoCharName
- });
+ list.Add(new CultureDto(name, name, twoCharName, threeletterNames));
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 299f10544..2c4d6884d 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -414,7 +414,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value));
}
- await ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false);
+ await ScheduledTask.ExecuteAsync(progress, CurrentCancellationTokenSource.Token).ConfigureAwait(false);
status = TaskCompletionStatus.Completed;
}
@@ -757,6 +757,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
var trigger = triggerInfo.Item2;
trigger.Triggered -= OnTriggerTriggered;
trigger.Stop();
+ if (trigger is IDisposable disposable)
+ {
+ disposable.Dispose();
+ }
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index a5786a3d7..0bf0838fa 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -88,13 +88,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var videos = _libraryManager.GetItemList(new InternalItemsQuery
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
index 79886cb52..776079044 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
@@ -57,12 +57,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
public bool IsLogged => true;
/// <inheritdoc />
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
if (!retentionDays.HasValue || retentionDays < 0)
{
- throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
+ throw new InvalidOperationException($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
}
var startDate = DateTime.UtcNow.AddDays(-retentionDays.Value);
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 0941902fc..03935b384 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -79,19 +79,14 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var minDateModified = DateTime.UtcNow.AddDays(-30);
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.CachePath, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(_applicationPaths.CachePath, minDateModified, progress, cancellationToken);
}
catch (DirectoryNotFoundException)
{
@@ -104,7 +99,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.TempDirectory, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(_applicationPaths.TempDirectory, minDateModified, progress, cancellationToken);
}
catch (DirectoryNotFoundException)
{
@@ -117,11 +112,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary>
/// Deletes the cache files from directory with a last write time less than a given date.
/// </summary>
- /// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param>
- private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
+ /// <param name="cancellationToken">The task cancellation token.</param>
+ private void DeleteCacheFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{
var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
index fedb5deb0..9739d7327 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
// Delete log files more than n days old
var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays);
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
index 099d781cd..e4e565c64 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
@@ -78,18 +78,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var minDateModified = DateTime.UtcNow.AddDays(-1);
progress.Report(50);
- DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodePath(), minDateModified, progress);
+ DeleteTempFilesFromDirectory(_configurationManager.GetTranscodePath(), minDateModified, progress, cancellationToken);
return Task.CompletedTask;
}
@@ -97,11 +92,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary>
/// Deletes the transcoded temp files from directory with a last write time less than a given date.
/// </summary>
- /// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param>
- private void DeleteTempFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
+ /// <param name="cancellationToken">The task cancellation token.</param>
+ private void DeleteTempFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{
var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
index 35a4aeef6..98e45fa46 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/OptimizeDatabaseTask.cs
@@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
_logger.LogInformation("Optimizing and vacuuming jellyfin.db...");
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
index 34780111b..7d60ea731 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs
@@ -62,15 +62,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Returns the task to be executed.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
- return _libraryManager.ValidatePeople(cancellationToken, progress);
+ return _libraryManager.ValidatePeopleAsync(progress, cancellationToken);
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
index b3973cecb..443649e6e 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -68,13 +68,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks };
}
- /// <summary>
- /// Update installed plugins.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns><see cref="Task" />.</returns>
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
progress.Report(0);
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
index 7c27ae384..065008157 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs
@@ -58,13 +58,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
- /// <summary>
- /// Executes the internal.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ /// <inheritdoc />
+ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index dc5eb7391..63f11a22c 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
@@ -8,10 +8,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that fires everyday.
/// </summary>
- public sealed class DailyTrigger : ITaskTrigger
+ public sealed class DailyTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _timeOfDay;
private Timer? _timer;
+ private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="DailyTrigger"/> class.
@@ -71,6 +72,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
+ _timer = null;
}
/// <summary>
@@ -80,5 +82,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{
Triggered?.Invoke(this, EventArgs.Empty);
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ DisposeTimer();
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index 927f57e95..3eb800199 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
@@ -9,11 +9,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that runs repeatedly on an interval.
/// </summary>
- public sealed class IntervalTrigger : ITaskTrigger
+ public sealed class IntervalTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _interval;
private DateTime _lastStartDate;
private Timer? _timer;
+ private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="IntervalTrigger"/> class.
@@ -89,6 +90,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
+ _timer = null;
}
/// <summary>
@@ -104,5 +106,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
Triggered(this, EventArgs.Empty);
}
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ DisposeTimer();
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index 2392b20fd..fab49f2fb 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
@@ -8,11 +8,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that fires on a weekly basis.
/// </summary>
- public sealed class WeeklyTrigger : ITaskTrigger
+ public sealed class WeeklyTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _timeOfDay;
private readonly DayOfWeek _dayOfWeek;
private Timer? _timer;
+ private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="WeeklyTrigger"/> class.
@@ -94,6 +95,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
+ _timer = null;
}
/// <summary>
@@ -103,5 +105,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{
Triggered?.Invoke(this, EventArgs.Empty);
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ DisposeTimer();
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index a18af27f3..a47650a32 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.TV
var currentUser = user;
var allNextUp = seriesKeys
- .Select(i => GetNextUp(i, currentUser, dtoOptions));
+ .Select(i => GetNextUp(i, currentUser, dtoOptions, request.Rewatching));
// If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view)
@@ -186,9 +186,9 @@ namespace Emby.Server.Implementations.TV
/// Gets the next up.
/// </summary>
/// <returns>Task{Episode}.</returns>
- private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions)
+ private Tuple<DateTime, Func<Episode>> GetNextUp(string seriesKey, User user, DtoOptions dtoOptions, bool rewatching)
{
- var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var lastQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
@@ -202,23 +202,43 @@ namespace Emby.Server.Implementations.TV
Fields = new[] { ItemFields.SortName },
EnableImages = false
}
- }).Cast<Episode>().FirstOrDefault();
+ };
+
+ if (rewatching)
+ {
+ // find last watched by date played, not by newest episode watched
+ lastQuery.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) };
+ }
+
+ var lastWatchedEpisode = _libraryManager.GetItemList(lastQuery).Cast<Episode>().FirstOrDefault();
Func<Episode> getEpisode = () =>
{
- var nextEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user)
+ var nextQuery = new InternalItemsQuery(user)
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
Limit = 1,
- IsPlayed = false,
+ IsPlayed = rewatching,
IsVirtualItem = false,
ParentIndexNumberNotEquals = 0,
MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
- }).Cast<Episode>().FirstOrDefault();
+ };
+
+ Episode nextEpisode;
+ if (rewatching)
+ {
+ nextQuery.Limit = 2;
+ // get watched episode after most recently watched
+ nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().ElementAtOrDefault(1);
+ }
+ else
+ {
+ nextEpisode = _libraryManager.GetItemList(nextQuery).Cast<Episode>().FirstOrDefault();
+ }
if (_configurationManager.Configuration.DisplaySpecialsWithinSeasons)
{
@@ -228,7 +248,7 @@ namespace Emby.Server.Implementations.TV
SeriesPresentationUniqueKey = seriesKey,
ParentIndexNumber = 0,
IncludeItemTypes = new[] { BaseItemKind.Episode },
- IsPlayed = false,
+ IsPlayed = rewatching,
IsVirtualItem = false,
DtoOptions = dtoOptions
})
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index c8ab99de4..937e792f5 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -9,6 +9,7 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.ApiClient;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
namespace Emby.Server.Implementations.Udp
{
@@ -18,11 +19,6 @@ namespace Emby.Server.Implementations.Udp
public sealed class UdpServer : IDisposable
{
/// <summary>
- /// Address Override Configuration Key.
- /// </summary>
- public const string AddressOverrideConfigKey = "PublishedServerUrl";
-
- /// <summary>
/// The _logger.
/// </summary>
private readonly ILogger _logger;
@@ -60,7 +56,7 @@ namespace Emby.Server.Implementations.Udp
private async Task RespondToV2Message(EndPoint endpoint, CancellationToken cancellationToken)
{
- string? localUrl = _config[AddressOverrideConfigKey];
+ string? localUrl = _config[AddressOverrideKey];
if (string.IsNullOrEmpty(localUrl))
{
localUrl = _appHost.GetSmartApiUrl(((IPEndPoint)endpoint).Address);
@@ -68,7 +64,7 @@ namespace Emby.Server.Implementations.Udp
if (string.IsNullOrEmpty(localUrl))
{
- _logger.LogWarning("Unable to respond to udp request because the local ip address could not be determined.");
+ _logger.LogWarning("Unable to respond to server discovery request because the local ip address could not be determined.");
return;
}