aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Naming/Audio/AudioFileParser.cs6
-rw-r--r--Emby.Naming/Emby.Naming.csproj5
-rw-r--r--Emby.Naming/Video/ExtraResolver.cs95
-rw-r--r--Emby.Naming/Video/VideoResolver.cs22
-rw-r--r--Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs8
-rw-r--r--Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs2
-rw-r--r--Emby.Server.Implementations/AppBase/ConfigurationHelper.cs2
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs2
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs2
-rw-r--r--Emby.Server.Implementations/Collections/CollectionImageProvider.cs4
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs2
-rw-r--r--Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs2
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptographyProvider.cs2
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs8
-rw-r--r--Emby.Server.Implementations/Data/ManagedConnection.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteExtensions.cs112
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs572
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs18
-rw-r--r--Emby.Server.Implementations/Data/TypeMapper.cs6
-rw-r--r--Emby.Server.Implementations/Devices/DeviceId.cs2
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs2
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs2
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj1
-rw-r--r--Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs54
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/SessionContext.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketManager.cs2
-rw-r--r--Emby.Server.Implementations/IO/FileRefresher.cs2
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs6
-rw-r--r--Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs2
-rw-r--r--Emby.Server.Implementations/IO/StreamHelper.cs2
-rw-r--r--Emby.Server.Implementations/IStartupOptions.cs1
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/DynamicImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/FolderImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/GenreImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Images/PlaylistImageProvider.cs2
-rw-r--r--Emby.Server.Implementations/Library/ExclusiveLiveStream.cs2
-rw-r--r--Emby.Server.Implementations/Library/IgnorePatterns.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/LiveStreamHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/MediaStreamSelector.cs2
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/PathExtensions.cs2
-rw-r--r--Emby.Server.Implementations/Library/ResolverHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs18
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs2
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs2
-rw-r--r--Emby.Server.Implementations/MediaEncoder/EncodingManager.cs2
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs2
-rw-r--r--Emby.Server.Implementations/Net/UdpSocket.cs2
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs2
-rw-r--r--Emby.Server.Implementations/Plugins/PluginManager.cs2
-rw-r--r--Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs6
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs2
-rw-r--r--Emby.Server.Implementations/Security/AuthenticationRepository.cs43
-rw-r--r--Emby.Server.Implementations/Serialization/MyXmlSerializer.cs10
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs2
-rw-r--r--Emby.Server.Implementations/Session/WebSocketController.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs4
-rw-r--r--Emby.Server.Implementations/Sorting/AlbumComparer.cs4
-rw-r--r--Emby.Server.Implementations/Sorting/ArtistComparer.cs4
-rw-r--r--Emby.Server.Implementations/Sorting/CommunityRatingComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/CriticRatingComparer.cs6
-rw-r--r--Emby.Server.Implementations/Sorting/DateCreatedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/DatePlayedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/IsFolderComparer.cs6
-rw-r--r--Emby.Server.Implementations/Sorting/IsPlayedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/NameComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/PlayCountComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/PremiereDateComparer.cs9
-rw-r--r--Emby.Server.Implementations/Sorting/ProductionYearComparer.cs9
-rw-r--r--Emby.Server.Implementations/Sorting/RandomComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/RuntimeComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/SortNameComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/StartDateComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/StudioComparer.cs2
-rw-r--r--Emby.Server.Implementations/SyncPlay/Group.cs2
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs2
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs2
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs2
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs2
-rw-r--r--Jellyfin.Api/Controllers/DynamicHlsController.cs58
-rw-r--r--Jellyfin.Api/Helpers/TranscodingJobHelper.cs5
-rw-r--r--Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs3
-rw-r--r--Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs11
-rw-r--r--Jellyfin.sln7
-rw-r--r--MediaBrowser.Common/Extensions/EnumerableExtensions.cs51
-rw-r--r--MediaBrowser.Controller/Extensions/StringExtensions.cs1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs49
-rw-r--r--MediaBrowser.Controller/Net/ISessionContext.cs4
-rw-r--r--MediaBrowser.Controller/Sorting/IBaseItemComparer.cs2
-rw-r--r--MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs17
-rw-r--r--MediaBrowser.Model/IO/IFileSystem.cs7
-rw-r--r--MediaBrowser.Model/IO/IShortcutHandler.cs2
-rw-r--r--MediaBrowser.Model/IO/IStreamHelper.cs2
-rw-r--r--MediaBrowser.Model/Tasks/ITaskTrigger.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs135
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs5
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs6
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs6
-rw-r--r--tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs58
-rw-r--r--tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs6
-rw-r--r--tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj37
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs96
-rw-r--r--tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs27
169 files changed, 1153 insertions, 728 deletions
diff --git a/Emby.Naming/Audio/AudioFileParser.cs b/Emby.Naming/Audio/AudioFileParser.cs
index 8b47dd12e..af4aa0059 100644
--- a/Emby.Naming/Audio/AudioFileParser.cs
+++ b/Emby.Naming/Audio/AudioFileParser.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
-using System.Linq;
using Emby.Naming.Common;
+using MediaBrowser.Common.Extensions;
namespace Emby.Naming.Audio
{
@@ -18,8 +18,8 @@ namespace Emby.Naming.Audio
/// <returns>True if file at path is audio file.</returns>
public static bool IsAudioFile(string path, NamingOptions options)
{
- var extension = Path.GetExtension(path);
- return options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
+ var extension = Path.GetExtension(path.AsSpan());
+ return options.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase);
}
}
}
diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj
index 63116f368..3224ff412 100644
--- a/Emby.Naming/Emby.Naming.csproj
+++ b/Emby.Naming/Emby.Naming.csproj
@@ -23,11 +23,12 @@
</PropertyGroup>
<ItemGroup>
- <Compile Include="..\SharedVersion.cs" />
+ <Compile Include="../SharedVersion.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
+ <ProjectReference Include="../MediaBrowser.Common/MediaBrowser.Common.csproj" />
+ <ProjectReference Include="../MediaBrowser.Model/MediaBrowser.Model.csproj" />
</ItemGroup>
<PropertyGroup>
diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs
index 1d3b36a1a..f9d06c09b 100644
--- a/Emby.Naming/Video/ExtraResolver.cs
+++ b/Emby.Naming/Video/ExtraResolver.cs
@@ -30,69 +30,72 @@ namespace Emby.Naming.Video
/// <returns>Returns <see cref="ExtraResult"/> object.</returns>
public ExtraResult GetExtraInfo(string path)
{
- return _options.VideoExtraRules
- .Select(i => GetExtraInfo(path, i))
- .FirstOrDefault(i => i.ExtraType != null) ?? new ExtraResult();
- }
-
- private ExtraResult GetExtraInfo(string path, ExtraRule rule)
- {
var result = new ExtraResult();
- if (rule.MediaType == MediaType.Audio)
+ for (var i = 0; i < _options.VideoExtraRules.Length; i++)
{
- if (!AudioFileParser.IsAudioFile(path, _options))
+ var rule = _options.VideoExtraRules[i];
+ if (rule.MediaType == MediaType.Audio)
{
- return result;
+ if (!AudioFileParser.IsAudioFile(path, _options))
+ {
+ continue;
+ }
}
- }
- else if (rule.MediaType == MediaType.Video)
- {
- if (!new VideoResolver(_options).IsVideoFile(path))
+ else if (rule.MediaType == MediaType.Video)
{
- return result;
+ if (!new VideoResolver(_options).IsVideoFile(path))
+ {
+ continue;
+ }
}
- }
-
- if (rule.RuleType == ExtraRuleType.Filename)
- {
- var filename = Path.GetFileNameWithoutExtension(path);
- if (string.Equals(filename, rule.Token, StringComparison.OrdinalIgnoreCase))
+ var pathSpan = path.AsSpan();
+ if (rule.RuleType == ExtraRuleType.Filename)
{
- result.ExtraType = rule.ExtraType;
- result.Rule = rule;
- }
- }
- else if (rule.RuleType == ExtraRuleType.Suffix)
- {
- var filename = Path.GetFileNameWithoutExtension(path);
+ var filename = Path.GetFileNameWithoutExtension(pathSpan);
- if (filename.IndexOf(rule.Token, StringComparison.OrdinalIgnoreCase) > 0)
+ if (filename.Equals(rule.Token, StringComparison.OrdinalIgnoreCase))
+ {
+ result.ExtraType = rule.ExtraType;
+ result.Rule = rule;
+ }
+ }
+ else if (rule.RuleType == ExtraRuleType.Suffix)
{
- result.ExtraType = rule.ExtraType;
- result.Rule = rule;
+ var filename = Path.GetFileNameWithoutExtension(pathSpan);
+
+ if (filename.Contains(rule.Token, StringComparison.OrdinalIgnoreCase))
+ {
+ result.ExtraType = rule.ExtraType;
+ result.Rule = rule;
+ }
}
- }
- else if (rule.RuleType == ExtraRuleType.Regex)
- {
- var filename = Path.GetFileName(path);
+ else if (rule.RuleType == ExtraRuleType.Regex)
+ {
+ var filename = Path.GetFileName(path);
- var regex = new Regex(rule.Token, RegexOptions.IgnoreCase);
+ var regex = new Regex(rule.Token, RegexOptions.IgnoreCase);
- if (regex.IsMatch(filename))
+ if (regex.IsMatch(filename))
+ {
+ result.ExtraType = rule.ExtraType;
+ result.Rule = rule;
+ }
+ }
+ else if (rule.RuleType == ExtraRuleType.DirectoryName)
{
- result.ExtraType = rule.ExtraType;
- result.Rule = rule;
+ var directoryName = Path.GetFileName(Path.GetDirectoryName(pathSpan));
+ if (directoryName.Equals(rule.Token, StringComparison.OrdinalIgnoreCase))
+ {
+ result.ExtraType = rule.ExtraType;
+ result.Rule = rule;
+ }
}
- }
- else if (rule.RuleType == ExtraRuleType.DirectoryName)
- {
- var directoryName = Path.GetFileName(Path.GetDirectoryName(path));
- if (string.Equals(directoryName, rule.Token, StringComparison.OrdinalIgnoreCase))
+
+ if (result.ExtraType != null)
{
- result.ExtraType = rule.ExtraType;
- result.Rule = rule;
+ return result;
}
}
diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs
index 79a6da8f7..27e73208c 100644
--- a/Emby.Naming/Video/VideoResolver.cs
+++ b/Emby.Naming/Video/VideoResolver.cs
@@ -1,8 +1,8 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
-using System.Linq;
using Emby.Naming.Common;
+using MediaBrowser.Common.Extensions;
namespace Emby.Naming.Video
{
@@ -59,15 +59,15 @@ namespace Emby.Naming.Video
}
bool isStub = false;
- string? container = null;
+ ReadOnlySpan<char> container = ReadOnlySpan<char>.Empty;
string? stubType = null;
if (!isDirectory)
{
- var extension = Path.GetExtension(path);
+ var extension = Path.GetExtension(path.AsSpan());
// Check supported extensions
- if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+ if (!_options.VideoFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
{
// It's not supported. Check stub extensions
if (!StubResolver.TryResolveFile(path, _options, out stubType))
@@ -86,9 +86,7 @@ namespace Emby.Naming.Video
var extraResult = new ExtraResolver(_options).GetExtraInfo(path);
- var name = isDirectory
- ? Path.GetFileName(path)
- : Path.GetFileNameWithoutExtension(path);
+ var name = Path.GetFileNameWithoutExtension(path);
int? year = null;
@@ -107,7 +105,7 @@ namespace Emby.Naming.Video
return new VideoFileInfo(
path: path,
- container: container,
+ container: container.IsEmpty ? null : container.ToString(),
isStub: isStub,
name: name,
year: year,
@@ -126,8 +124,8 @@ namespace Emby.Naming.Video
/// <returns>True if is video file.</returns>
public bool IsVideoFile(string path)
{
- var extension = Path.GetExtension(path);
- return _options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
+ var extension = Path.GetExtension(path.AsSpan());
+ return _options.VideoFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -137,8 +135,8 @@ namespace Emby.Naming.Video
/// <returns>True if is video file stub.</returns>
public bool IsStubFile(string path)
{
- var extension = Path.GetExtension(path);
- return _options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
+ var extension = Path.GetExtension(path.AsSpan());
+ return _options.StubFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 660bbb2de..6edfad575 100644
--- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -33,7 +33,7 @@ namespace Emby.Server.Implementations.AppBase
CachePath = cacheDirectoryPath;
WebPath = webDirectoryPath;
- DataPath = Path.Combine(ProgramDataPath, "data");
+ _dataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName;
}
/// <summary>
@@ -55,11 +55,7 @@ namespace Emby.Server.Implementations.AppBase
/// Gets the folder path to the data directory.
/// </summary>
/// <value>The data directory.</value>
- public string DataPath
- {
- get => _dataPath;
- private set => _dataPath = Directory.CreateDirectory(value).FullName;
- }
+ public string DataPath => _dataPath;
/// <inheritdoc />
public string VirtualDataPath => "%AppDataPath%";
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index 4f72c8ce1..8c919db43 100644
--- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
index 29bac6634..de770f59e 100644
--- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
+++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.IO;
using System.Linq;
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 75d8fc113..82995deb3 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 7324b0ee9..448f12403 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
index c69a07e83..ca8409402 100644
--- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -82,9 +82,9 @@ namespace Emby.Server.Implementations.Collections
return null;
})
.Where(i => i != null)
- .GroupBy(x => x.Id)
+ .GroupBy(x => x!.Id) // We removed the null values
.Select(x => x.First())
- .ToList();
+ .ToList()!; // Again... the list doesn't contain any null values
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index c56f33448..82d80fc83 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 7a8ed8c29..ff5602f24 100644
--- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Globalization;
using System.IO;
diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
index 12a9e44e7..4a9b28085 100644
--- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
+++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index 8c756a7f4..6f23a0888 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -181,11 +183,9 @@ namespace Emby.Server.Implementations.Data
foreach (var row in connection.Query("PRAGMA table_info(" + table + ")"))
{
- if (row[1].SQLiteType != SQLiteType.Null)
+ if (row.TryGetString(1, out var columnName))
{
- var name = row[1].ToString();
-
- columnNames.Add(name);
+ columnNames.Add(columnName);
}
}
diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs
index 5c094ddd2..10c6f837e 100644
--- a/Emby.Server.Implementations/Data/ManagedConnection.cs
+++ b/Emby.Server.Implementations/Data/ManagedConnection.cs
@@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Data
{
public class ManagedConnection : IDisposable
{
- private SQLiteDatabaseConnection _db;
+ private SQLiteDatabaseConnection? _db;
private readonly SemaphoreSlim _writeLock;
private bool _disposed = false;
diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs
index a04d63088..e532825af 100644
--- a/Emby.Server.Implementations/Data/SqliteExtensions.cs
+++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs
@@ -1,8 +1,10 @@
+#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using SQLitePCL.pretty;
@@ -96,21 +98,43 @@ namespace Emby.Server.Implementations.Data
DateTimeStyles.None).ToUniversalTime();
}
- public static DateTime? TryReadDateTime(this IResultSetValue result)
+ public static bool TryReadDateTime(this IReadOnlyList<IResultSetValue> reader, int index, out DateTime result)
{
- var dateText = result.ToString();
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ var dateText = item.ToString();
if (DateTime.TryParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out var dateTimeResult))
{
- return dateTimeResult.ToUniversalTime();
+ result = dateTimeResult.ToUniversalTime();
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ public static bool TryGetGuid(this IReadOnlyList<IResultSetValue> reader, int index, out Guid result)
+ {
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
}
- return null;
+ result = item.ReadGuidFromBlob();
+ return true;
}
- public static bool IsDBNull(this IReadOnlyList<IResultSetValue> result, int index)
+ public static bool IsDbNull(this IResultSetValue result)
{
- return result[index].SQLiteType == SQLiteType.Null;
+ return result.SQLiteType == SQLiteType.Null;
}
public static string GetString(this IReadOnlyList<IResultSetValue> result, int index)
@@ -118,14 +142,48 @@ namespace Emby.Server.Implementations.Data
return result[index].ToString();
}
+ public static bool TryGetString(this IReadOnlyList<IResultSetValue> reader, int index, out string result)
+ {
+ result = null;
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ return false;
+ }
+
+ result = item.ToString();
+ return true;
+ }
+
public static bool GetBoolean(this IReadOnlyList<IResultSetValue> result, int index)
{
return result[index].ToBool();
}
- public static int GetInt32(this IReadOnlyList<IResultSetValue> result, int index)
+ public static bool TryGetBoolean(this IReadOnlyList<IResultSetValue> reader, int index, out bool result)
+ {
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ result = item.ToBool();
+ return true;
+ }
+
+ public static bool TryGetInt32(this IReadOnlyList<IResultSetValue> reader, int index, out int result)
{
- return result[index].ToInt();
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ result = item.ToInt();
+ return true;
}
public static long GetInt64(this IReadOnlyList<IResultSetValue> result, int index)
@@ -133,9 +191,43 @@ namespace Emby.Server.Implementations.Data
return result[index].ToInt64();
}
- public static float GetFloat(this IReadOnlyList<IResultSetValue> result, int index)
+ public static bool TryGetInt64(this IReadOnlyList<IResultSetValue> reader, int index, out long result)
+ {
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ result = item.ToInt64();
+ return true;
+ }
+
+ public static bool TryGetSingle(this IReadOnlyList<IResultSetValue> reader, int index, out float result)
+ {
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ result = item.ToFloat();
+ return true;
+ }
+
+ public static bool TryGetDouble(this IReadOnlyList<IResultSetValue> reader, int index, out double result)
{
- return result[index].ToFloat();
+ var item = reader[index];
+ if (item.IsDbNull())
+ {
+ result = default;
+ return false;
+ }
+
+ result = item.ToDouble();
+ return true;
}
public static Guid GetGuid(this IReadOnlyList<IResultSetValue> result, int index)
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 4ae7a842c..5b4bbb339 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -1332,27 +1334,23 @@ namespace Emby.Server.Implementations.Data
if (queryHasStartDate)
{
- if (!reader.IsDBNull(index))
+ if (item is IHasStartDate hasStartDate && reader.TryReadDateTime(index, out var startDate))
{
- if (item is IHasStartDate hasStartDate)
- {
- hasStartDate.StartDate = reader[index].ReadDateTime();
- }
+ hasStartDate.StartDate = startDate;
}
index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var endDate))
{
- item.EndDate = reader[index].TryReadDateTime();
+ item.EndDate = endDate;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ var channelId = reader[index];
+ if (!channelId.IsDbNull())
{
- if (!Utf8Parser.TryParse(reader[index].ToBlob(), out Guid value, out _, standardFormat: 'N'))
+ if (!Utf8Parser.TryParse(channelId.ToBlob(), out Guid value, out _, standardFormat: 'N'))
{
var str = reader.GetString(index);
Logger.LogWarning("{ChannelId} isn't in the expected format", str);
@@ -1368,33 +1366,25 @@ namespace Emby.Server.Implementations.Data
{
if (item is IHasProgramAttributes hasProgramAttributes)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isMovie))
{
- hasProgramAttributes.IsMovie = reader.GetBoolean(index);
+ hasProgramAttributes.IsMovie = isMovie;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isSeries))
{
- hasProgramAttributes.IsSeries = reader.GetBoolean(index);
+ hasProgramAttributes.IsSeries = isSeries;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var episodeTitle))
{
- hasProgramAttributes.EpisodeTitle = reader.GetString(index);
+ hasProgramAttributes.EpisodeTitle = episodeTitle;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isRepeat))
{
- hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
+ hasProgramAttributes.IsRepeat = isRepeat;
}
-
- index++;
}
else
{
@@ -1402,242 +1392,190 @@ namespace Emby.Server.Implementations.Data
}
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetSingle(index++, out var communityRating))
{
- item.CommunityRating = reader.GetFloat(index);
+ item.CommunityRating = communityRating;
}
- index++;
-
if (HasField(query, ItemFields.CustomRating))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var customRating))
{
- item.CustomRating = reader.GetString(index);
+ item.CustomRating = customRating;
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var indexNumber))
{
- item.IndexNumber = reader.GetInt32(index);
+ item.IndexNumber = indexNumber;
}
- index++;
-
if (HasField(query, ItemFields.Settings))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isLocked))
{
- item.IsLocked = reader.GetBoolean(index);
+ item.IsLocked = isLocked;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var preferredMetadataLanguage))
{
- item.PreferredMetadataLanguage = reader.GetString(index);
+ item.PreferredMetadataLanguage = preferredMetadataLanguage;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var preferredMetadataCountryCode))
{
- item.PreferredMetadataCountryCode = reader.GetString(index);
+ item.PreferredMetadataCountryCode = preferredMetadataCountryCode;
}
-
- index++;
}
if (HasField(query, ItemFields.Width))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var width))
{
- item.Width = reader.GetInt32(index);
+ item.Width = width;
}
-
- index++;
}
if (HasField(query, ItemFields.Height))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var height))
{
- item.Height = reader.GetInt32(index);
+ item.Height = height;
}
-
- index++;
}
if (HasField(query, ItemFields.DateLastRefreshed))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var dateLastRefreshed))
{
- item.DateLastRefreshed = reader[index].ReadDateTime();
+ item.DateLastRefreshed = dateLastRefreshed;
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var name))
{
- item.Name = reader.GetString(index);
+ item.Name = name;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var restorePath))
{
- item.Path = RestorePath(reader.GetString(index));
+ item.Path = RestorePath(restorePath);
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var premiereDate))
{
- item.PremiereDate = reader[index].TryReadDateTime();
+ item.PremiereDate = premiereDate;
}
- index++;
-
if (HasField(query, ItemFields.Overview))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var overview))
{
- item.Overview = reader.GetString(index);
+ item.Overview = overview;
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var parentIndexNumber))
{
- item.ParentIndexNumber = reader.GetInt32(index);
+ item.ParentIndexNumber = parentIndexNumber;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var productionYear))
{
- item.ProductionYear = reader.GetInt32(index);
+ item.ProductionYear = productionYear;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var officialRating))
{
- item.OfficialRating = reader.GetString(index);
+ item.OfficialRating = officialRating;
}
- index++;
-
if (HasField(query, ItemFields.SortName))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var forcedSortName))
{
- item.ForcedSortName = reader.GetString(index);
+ item.ForcedSortName = forcedSortName;
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt64(index++, out var runTimeTicks))
{
- item.RunTimeTicks = reader.GetInt64(index);
+ item.RunTimeTicks = runTimeTicks;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt64(index++, out var size))
{
- item.Size = reader.GetInt64(index);
+ item.Size = size;
}
- index++;
-
if (HasField(query, ItemFields.DateCreated))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var dateCreated))
{
- item.DateCreated = reader[index].ReadDateTime();
+ item.DateCreated = dateCreated;
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var dateModified))
{
- item.DateModified = reader[index].ReadDateTime();
+ item.DateModified = dateModified;
}
- index++;
-
- item.Id = reader.GetGuid(index);
- index++;
+ item.Id = reader.GetGuid(index++);
if (HasField(query, ItemFields.Genres))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var genres))
{
- item.Genres = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries);
+ item.Genres = genres.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetGuid(index++, out var parentId))
{
- item.ParentId = reader.GetGuid(index);
+ item.ParentId = parentId;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var audioString))
{
- if (Enum.TryParse(reader.GetString(index), true, out ProgramAudio audio))
+ // TODO Span overload coming in the future https://github.com/dotnet/runtime/issues/1916
+ if (Enum.TryParse(audioString, true, out ProgramAudio audio))
{
item.Audio = audio;
}
}
- index++;
-
// TODO: Even if not needed by apps, the server needs it internally
// But get this excluded from contexts where it is not needed
if (hasServiceName)
{
if (item is LiveTvChannel liveTvChannel)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var serviceName))
{
- liveTvChannel.ServiceName = reader.GetString(index);
+ liveTvChannel.ServiceName = serviceName;
}
}
index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isInMixedFolder))
{
- item.IsInMixedFolder = reader.GetBoolean(index);
+ item.IsInMixedFolder = isInMixedFolder;
}
- index++;
-
if (HasField(query, ItemFields.DateLastSaved))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryReadDateTime(index++, out var dateLastSaved))
{
- item.DateLastSaved = reader[index].ReadDateTime();
+ item.DateLastSaved = dateLastSaved;
}
-
- index++;
}
if (HasField(query, ItemFields.Settings))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var lockedFields))
{
IEnumerable<MetadataField> GetLockedFields(string s)
{
@@ -1650,37 +1588,31 @@ namespace Emby.Server.Implementations.Data
}
}
- item.LockedFields = GetLockedFields(reader.GetString(index)).ToArray();
+ item.LockedFields = GetLockedFields(lockedFields).ToArray();
}
-
- index++;
}
if (HasField(query, ItemFields.Studios))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var studios))
{
- item.Studios = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries);
+ item.Studios = studios.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
-
- index++;
}
if (HasField(query, ItemFields.Tags))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var tags))
{
- item.Tags = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries);
+ item.Tags = tags.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
-
- index++;
}
if (hasTrailerTypes)
{
if (item is Trailer trailer)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var trailerTypes))
{
IEnumerable<TrailerType> GetTrailerTypes(string s)
{
@@ -1693,7 +1625,7 @@ namespace Emby.Server.Implementations.Data
}
}
- trailer.TrailerTypes = GetTrailerTypes(reader.GetString(index)).ToArray();
+ trailer.TrailerTypes = GetTrailerTypes(trailerTypes).ToArray();
}
}
@@ -1702,19 +1634,17 @@ namespace Emby.Server.Implementations.Data
if (HasField(query, ItemFields.OriginalTitle))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var originalTitle))
{
- item.OriginalTitle = reader.GetString(index);
+ item.OriginalTitle = originalTitle;
}
-
- index++;
}
if (item is Video video)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var primaryVersionId))
{
- video.PrimaryVersionId = reader.GetString(index);
+ video.PrimaryVersionId = primaryVersionId;
}
}
@@ -1722,40 +1652,34 @@ namespace Emby.Server.Implementations.Data
if (HasField(query, ItemFields.DateLastMediaAdded))
{
- if (item is Folder folder && !reader.IsDBNull(index))
+ if (item is Folder folder && reader.TryReadDateTime(index, out var dateLastMediaAdded))
{
- folder.DateLastMediaAdded = reader[index].TryReadDateTime();
+ folder.DateLastMediaAdded = dateLastMediaAdded;
}
index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var album))
{
- item.Album = reader.GetString(index);
+ item.Album = album;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetSingle(index++, out var criticRating))
{
- item.CriticRating = reader.GetFloat(index);
+ item.CriticRating = criticRating;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetBoolean(index++, out var isVirtualItem))
{
- item.IsVirtualItem = reader.GetBoolean(index);
+ item.IsVirtualItem = isVirtualItem;
}
- index++;
-
if (item is IHasSeries hasSeriesName)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var seriesName))
{
- hasSeriesName.SeriesName = reader.GetString(index);
+ hasSeriesName.SeriesName = seriesName;
}
}
@@ -1765,15 +1689,15 @@ namespace Emby.Server.Implementations.Data
{
if (item is Episode episode)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var seasonName))
{
- episode.SeasonName = reader.GetString(index);
+ episode.SeasonName = seasonName;
}
index++;
- if (!reader.IsDBNull(index))
+ if (reader.TryGetGuid(index, out var seasonId))
{
- episode.SeasonId = reader.GetGuid(index);
+ episode.SeasonId = seasonId;
}
}
else
@@ -1789,9 +1713,9 @@ namespace Emby.Server.Implementations.Data
{
if (hasSeries != null)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetGuid(index, out var seriesId))
{
- hasSeries.SeriesId = reader.GetGuid(index);
+ hasSeries.SeriesId = seriesId;
}
}
@@ -1800,56 +1724,48 @@ namespace Emby.Server.Implementations.Data
if (HasField(query, ItemFields.PresentationUniqueKey))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var presentationUniqueKey))
{
- item.PresentationUniqueKey = reader.GetString(index);
+ item.PresentationUniqueKey = presentationUniqueKey;
}
-
- index++;
}
if (HasField(query, ItemFields.InheritedParentalRatingValue))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var parentalRating))
{
- item.InheritedParentalRatingValue = reader.GetInt32(index);
+ item.InheritedParentalRatingValue = parentalRating;
}
-
- index++;
}
if (HasField(query, ItemFields.ExternalSeriesId))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var externalSeriesId))
{
- item.ExternalSeriesId = reader.GetString(index);
+ item.ExternalSeriesId = externalSeriesId;
}
-
- index++;
}
if (HasField(query, ItemFields.Taglines))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var tagLine))
{
- item.Tagline = reader.GetString(index);
+ item.Tagline = tagLine;
}
-
- index++;
}
- if (item.ProviderIds.Count == 0 && !reader.IsDBNull(index))
+ if (item.ProviderIds.Count == 0 && reader.TryGetString(index, out var providerIds))
{
- DeserializeProviderIds(reader.GetString(index), item);
+ DeserializeProviderIds(providerIds, item);
}
index++;
if (query.DtoOptions.EnableImages)
{
- if (item.ImageInfos.Length == 0 && !reader.IsDBNull(index))
+ if (item.ImageInfos.Length == 0 && reader.TryGetString(index, out var imageInfos))
{
- item.ImageInfos = DeserializeImages(reader.GetString(index));
+ item.ImageInfos = DeserializeImages(imageInfos);
}
index++;
@@ -1857,72 +1773,62 @@ namespace Emby.Server.Implementations.Data
if (HasField(query, ItemFields.ProductionLocations))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var productionLocations))
{
- item.ProductionLocations = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries).ToArray();
+ item.ProductionLocations = productionLocations.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
-
- index++;
}
if (HasField(query, ItemFields.ExtraIds))
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var extraIds))
{
- item.ExtraIds = SplitToGuids(reader.GetString(index));
+ item.ExtraIds = SplitToGuids(extraIds);
}
-
- index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetInt32(index++, out var totalBitrate))
{
- item.TotalBitrate = reader.GetInt32(index);
+ item.TotalBitrate = totalBitrate;
}
- index++;
-
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var extraTypeString))
{
- if (Enum.TryParse(reader.GetString(index), true, out ExtraType extraType))
+ if (Enum.TryParse(extraTypeString, true, out ExtraType extraType))
{
item.ExtraType = extraType;
}
}
- index++;
-
if (hasArtistFields)
{
- if (item is IHasArtist hasArtists && !reader.IsDBNull(index))
+ if (item is IHasArtist hasArtists && reader.TryGetString(index, out var artists))
{
- hasArtists.Artists = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries);
+ hasArtists.Artists = artists.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
index++;
- if (item is IHasAlbumArtist hasAlbumArtists && !reader.IsDBNull(index))
+ if (item is IHasAlbumArtist hasAlbumArtists && reader.TryGetString(index, out var albumArtists))
{
- hasAlbumArtists.AlbumArtists = reader.GetString(index).Split('|', StringSplitOptions.RemoveEmptyEntries);
+ hasAlbumArtists.AlbumArtists = albumArtists.Split('|', StringSplitOptions.RemoveEmptyEntries);
}
index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index++, out var externalId))
{
- item.ExternalId = reader.GetString(index);
+ item.ExternalId = externalId;
}
- index++;
-
if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
{
if (hasSeries != null)
{
- if (!reader.IsDBNull(index))
+ if (reader.TryGetString(index, out var seriesPresentationUniqueKey))
{
- hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
+ hasSeries.SeriesPresentationUniqueKey = seriesPresentationUniqueKey;
}
}
@@ -1931,21 +1837,19 @@ namespace Emby.Server.Implementations.Data
if (enableProgramAttributes)
{
- if (item is LiveTvProgram program && !reader.IsDBNull(index))
+ if (item is LiveTvProgram program && reader.TryGetString(index, out var showId))
{
- program.ShowId = reader.GetString(index);
+ program.ShowId = showId;
}
index++;
}
- if (!reader.IsDBNull(index))
+ if (reader.TryGetGuid(index, out var ownerId))
{
- item.OwnerId = reader.GetGuid(index);
+ item.OwnerId = ownerId;
}
- index++;
-
return item;
}
@@ -2032,14 +1936,14 @@ namespace Emby.Server.Implementations.Data
StartPositionTicks = reader.GetInt64(0)
};
- if (!reader.IsDBNull(1))
+ if (reader.TryGetString(1, out var chapterName))
{
- chapter.Name = reader.GetString(1);
+ chapter.Name = chapterName;
}
- if (!reader.IsDBNull(2))
+ if (reader.TryGetString(2, out var imagePath))
{
- chapter.ImagePath = reader.GetString(2);
+ chapter.ImagePath = imagePath;
if (!string.IsNullOrEmpty(chapter.ImagePath))
{
@@ -2054,9 +1958,9 @@ namespace Emby.Server.Implementations.Data
}
}
- if (!reader.IsDBNull(3))
+ if (reader.TryReadDateTime(3, out var imageDateModified))
{
- chapter.ImageDateModified = reader[3].ReadDateTime();
+ chapter.ImageDateModified = imageDateModified;
}
return chapter;
@@ -3228,12 +3132,8 @@ namespace Emby.Server.Implementations.Data
foreach (var row in statement.ExecuteQuery())
{
var id = row.GetGuid(0);
- string path = null;
- if (!row.IsDBNull(1))
- {
- path = row.GetString(1);
- }
+ row.TryGetString(1, out var path);
list.Add(new Tuple<Guid, string>(id, path));
}
@@ -5327,9 +5227,9 @@ AND Type = @InternalPersonType)");
{
foreach (var row in statement.ExecuteQuery())
{
- if (!row.IsDBNull(0))
+ if (row.TryGetString(0, out var result))
{
- list.Add(row.GetString(0));
+ list.Add(result);
}
}
}
@@ -5603,7 +5503,7 @@ AND Type = @InternalPersonType)");
return result;
}
- private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, string[] typesToCount)
+ private static ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, string[] typesToCount)
{
var counts = new ItemCounts();
@@ -5612,51 +5512,43 @@ AND Type = @InternalPersonType)");
return counts;
}
- var typeString = reader.IsDBNull(countStartColumn) ? null : reader.GetString(countStartColumn);
-
- if (string.IsNullOrWhiteSpace(typeString))
+ if (!reader.TryGetString(countStartColumn, out var typeString))
{
return counts;
}
- var allTypes = typeString.Split('|', StringSplitOptions.RemoveEmptyEntries)
- .ToLookup(x => x);
-
- foreach (var type in allTypes)
+ foreach (var typeName in typeString.AsSpan().Split('|'))
{
- var value = type.Count();
- var typeName = type.Key;
-
- if (string.Equals(typeName, typeof(Series).FullName, StringComparison.OrdinalIgnoreCase))
+ if (typeName.Equals(typeof(Series).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.SeriesCount = value;
+ counts.SeriesCount++;
}
- else if (string.Equals(typeName, typeof(Episode).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(Episode).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.EpisodeCount = value;
+ counts.EpisodeCount++;
}
- else if (string.Equals(typeName, typeof(Movie).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(Movie).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.MovieCount = value;
+ counts.MovieCount++;
}
- else if (string.Equals(typeName, typeof(MusicAlbum).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(MusicAlbum).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.AlbumCount = value;
+ counts.AlbumCount++;
}
- else if (string.Equals(typeName, typeof(MusicArtist).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(MusicArtist).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.ArtistCount = value;
+ counts.ArtistCount++;
}
- else if (string.Equals(typeName, typeof(Audio).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(Audio).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.SongCount = value;
+ counts.SongCount++;
}
- else if (string.Equals(typeName, typeof(Trailer).FullName, StringComparison.OrdinalIgnoreCase))
+ else if (typeName.Equals(typeof(Trailer).FullName, StringComparison.OrdinalIgnoreCase))
{
- counts.TrailerCount = value;
+ counts.TrailerCount++;
}
- counts.ItemCount += value;
+ counts.ItemCount++;
}
return counts;
@@ -5850,19 +5742,19 @@ AND Type = @InternalPersonType)");
Name = reader.GetString(1)
};
- if (!reader.IsDBNull(2))
+ if (reader.TryGetString(2, out var role))
{
- item.Role = reader.GetString(2);
+ item.Role = role;
}
- if (!reader.IsDBNull(3))
+ if (reader.TryGetString(3, out var type))
{
- item.Type = reader.GetString(3);
+ item.Type = type;
}
- if (!reader.IsDBNull(4))
+ if (reader.TryGetInt32(4, out var sortOrder))
{
- item.SortOrder = reader.GetInt32(4);
+ item.SortOrder = sortOrder;
}
return item;
@@ -6058,150 +5950,150 @@ AND Type = @InternalPersonType)");
item.Type = Enum.Parse<MediaStreamType>(reader[2].ToString(), true);
- if (reader[3].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(3, out var codec))
{
- item.Codec = reader[3].ToString();
+ item.Codec = codec;
}
- if (reader[4].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(4, out var language))
{
- item.Language = reader[4].ToString();
+ item.Language = language;
}
- if (reader[5].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(5, out var channelLayout))
{
- item.ChannelLayout = reader[5].ToString();
+ item.ChannelLayout = channelLayout;
}
- if (reader[6].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(6, out var profile))
{
- item.Profile = reader[6].ToString();
+ item.Profile = profile;
}
- if (reader[7].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(7, out var aspectRatio))
{
- item.AspectRatio = reader[7].ToString();
+ item.AspectRatio = aspectRatio;
}
- if (reader[8].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(8, out var path))
{
- item.Path = RestorePath(reader[8].ToString());
+ item.Path = RestorePath(path);
}
item.IsInterlaced = reader.GetBoolean(9);
- if (reader[10].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(10, out var bitrate))
{
- item.BitRate = reader.GetInt32(10);
+ item.BitRate = bitrate;
}
- if (reader[11].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(11, out var channels))
{
- item.Channels = reader.GetInt32(11);
+ item.Channels = channels;
}
- if (reader[12].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(12, out var sampleRate))
{
- item.SampleRate = reader.GetInt32(12);
+ item.SampleRate = sampleRate;
}
item.IsDefault = reader.GetBoolean(13);
item.IsForced = reader.GetBoolean(14);
item.IsExternal = reader.GetBoolean(15);
- if (reader[16].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(16, out var width))
{
- item.Width = reader.GetInt32(16);
+ item.Width = width;
}
- if (reader[17].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(17, out var height))
{
- item.Height = reader.GetInt32(17);
+ item.Height = height;
}
- if (reader[18].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetSingle(18, out var averageFrameRate))
{
- item.AverageFrameRate = reader.GetFloat(18);
+ item.AverageFrameRate = averageFrameRate;
}
- if (reader[19].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetSingle(19, out var realFrameRate))
{
- item.RealFrameRate = reader.GetFloat(19);
+ item.RealFrameRate = realFrameRate;
}
- if (reader[20].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetSingle(20, out var level))
{
- item.Level = reader.GetFloat(20);
+ item.Level = level;
}
- if (reader[21].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(21, out var pixelFormat))
{
- item.PixelFormat = reader[21].ToString();
+ item.PixelFormat = pixelFormat;
}
- if (reader[22].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(22, out var bitDepth))
{
- item.BitDepth = reader.GetInt32(22);
+ item.BitDepth = bitDepth;
}
- if (reader[23].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetBoolean(23, out var isAnamorphic))
{
- item.IsAnamorphic = reader.GetBoolean(23);
+ item.IsAnamorphic = isAnamorphic;
}
- if (reader[24].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(24, out var refFrames))
{
- item.RefFrames = reader.GetInt32(24);
+ item.RefFrames = refFrames;
}
- if (reader[25].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(25, out var codecTag))
{
- item.CodecTag = reader.GetString(25);
+ item.CodecTag = codecTag;
}
- if (reader[26].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(26, out var comment))
{
- item.Comment = reader.GetString(26);
+ item.Comment = comment;
}
- if (reader[27].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(27, out var nalLengthSize))
{
- item.NalLengthSize = reader.GetString(27);
+ item.NalLengthSize = nalLengthSize;
}
- if (reader[28].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetBoolean(28, out var isAVC))
{
- item.IsAVC = reader[28].ToBool();
+ item.IsAVC = isAVC;
}
- if (reader[29].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(29, out var title))
{
- item.Title = reader[29].ToString();
+ item.Title = title;
}
- if (reader[30].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(30, out var timeBase))
{
- item.TimeBase = reader[30].ToString();
+ item.TimeBase = timeBase;
}
- if (reader[31].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(31, out var codecTimeBase))
{
- item.CodecTimeBase = reader[31].ToString();
+ item.CodecTimeBase = codecTimeBase;
}
- if (reader[32].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(32, out var colorPrimaries))
{
- item.ColorPrimaries = reader[32].ToString();
+ item.ColorPrimaries = colorPrimaries;
}
- if (reader[33].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(33, out var colorSpace))
{
- item.ColorSpace = reader[33].ToString();
+ item.ColorSpace = colorSpace;
}
- if (reader[34].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(34, out var colorTransfer))
{
- item.ColorTransfer = reader[34].ToString();
+ item.ColorTransfer = colorTransfer;
}
if (item.Type == MediaStreamType.Subtitle)
@@ -6357,29 +6249,29 @@ AND Type = @InternalPersonType)");
Index = reader[1].ToInt()
};
- if (reader[2].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(2, out var codec))
{
- item.Codec = reader[2].ToString();
+ item.Codec = codec;
}
- if (reader[2].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(3, out var codecTag))
{
- item.CodecTag = reader[3].ToString();
+ item.CodecTag = codecTag;
}
- if (reader[4].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(4, out var comment))
{
- item.Comment = reader[4].ToString();
+ item.Comment = comment;
}
- if (reader[6].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(5, out var fileName))
{
- item.FileName = reader[5].ToString();
+ item.FileName = fileName;
}
- if (reader[6].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(6, out var mimeType))
{
- item.MimeType = reader[6].ToString();
+ item.MimeType = mimeType;
}
return item;
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index 6574db607..1756bcae0 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -355,9 +357,9 @@ namespace Emby.Server.Implementations.Data
userData.Key = reader[0].ToString();
// userData.UserId = reader[1].ReadGuidFromBlob();
- if (reader[2].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetDouble(2, out var rating))
{
- userData.Rating = reader[2].ToDouble();
+ userData.Rating = rating;
}
userData.Played = reader[3].ToBool();
@@ -365,19 +367,19 @@ namespace Emby.Server.Implementations.Data
userData.IsFavorite = reader[5].ToBool();
userData.PlaybackPositionTicks = reader[6].ToInt64();
- if (reader[7].SQLiteType != SQLiteType.Null)
+ if (reader.TryReadDateTime(7, out var lastPlayedDate))
{
- userData.LastPlayedDate = reader[7].TryReadDateTime();
+ userData.LastPlayedDate = lastPlayedDate;
}
- if (reader[8].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(8, out var audioStreamIndex))
{
- userData.AudioStreamIndex = reader[8].ToInt();
+ userData.AudioStreamIndex = audioStreamIndex;
}
- if (reader[9].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetInt32(9, out var subtitleStreamIndex))
{
- userData.SubtitleStreamIndex = reader[9].ToInt();
+ userData.SubtitleStreamIndex = subtitleStreamIndex;
}
return userData;
diff --git a/Emby.Server.Implementations/Data/TypeMapper.cs b/Emby.Server.Implementations/Data/TypeMapper.cs
index 7044b1d19..7f1306d15 100644
--- a/Emby.Server.Implementations/Data/TypeMapper.cs
+++ b/Emby.Server.Implementations/Data/TypeMapper.cs
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.Data
/// This holds all the types in the running assemblies
/// so that we can de-serialize properly when we don't have strong types.
/// </summary>
- private readonly ConcurrentDictionary<string, Type> _typeMap = new ConcurrentDictionary<string, Type>();
+ private readonly ConcurrentDictionary<string, Type?> _typeMap = new ConcurrentDictionary<string, Type?>();
/// <summary>
/// Gets the type.
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="typeName">Name of the type.</param>
/// <returns>Type.</returns>
/// <exception cref="ArgumentNullException"><c>typeName</c> is null.</exception>
- public Type GetType(string typeName)
+ public Type? GetType(string typeName)
{
if (string.IsNullOrEmpty(typeName))
{
@@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Data
/// </summary>
/// <param name="typeName">Name of the type.</param>
/// <returns>Type.</returns>
- private Type LookupType(string typeName)
+ private Type? LookupType(string typeName)
{
return AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType(typeName))
diff --git a/Emby.Server.Implementations/Devices/DeviceId.cs b/Emby.Server.Implementations/Devices/DeviceId.cs
index fa6ac95fd..3d15b3e76 100644
--- a/Emby.Server.Implementations/Devices/DeviceId.cs
+++ b/Emby.Server.Implementations/Devices/DeviceId.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index da5047d24..2637addce 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 4ae35039a..7411239a1 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 14f6f565c..113863519 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -44,6 +44,7 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
<NoWarn>AD0001</NoWarn>
<AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode>
diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
index 14201ead2..cc3e4a2c2 100644
--- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
+++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index ae1b51b4c..5bb4100ba 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
index 824bb85f4..e0ca02d98 100644
--- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index 3624e079f..211941f44 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Net.Sockets;
using System.Threading;
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index 1989e9ed2..332fb3385 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 024404ceb..c87f7dbbd 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -2,8 +2,8 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
@@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
if (requestContext.Request.HttpContext.Items.TryGetValue("AuthorizationInfo", out var cached))
{
- return (AuthorizationInfo)cached;
+ return (AuthorizationInfo)cached!; // Cache should never contain null
}
return GetAuthorization(requestContext);
@@ -55,15 +55,15 @@ namespace Emby.Server.Implementations.HttpServer.Security
}
private AuthorizationInfo GetAuthorizationInfoFromDictionary(
- in Dictionary<string, string> auth,
+ in Dictionary<string, string>? auth,
in IHeaderDictionary headers,
in IQueryCollection queryString)
{
- string deviceId = null;
- string device = null;
- string client = null;
- string version = null;
- string token = null;
+ string? deviceId = null;
+ string? device = null;
+ string? client = null;
+ string? version = null;
+ string? token = null;
if (auth != null)
{
@@ -206,7 +206,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
- private Dictionary<string, string> GetAuthorizationDictionary(HttpContext httpReq)
+ private Dictionary<string, string>? GetAuthorizationDictionary(HttpContext httpReq)
{
var auth = httpReq.Request.Headers["X-Emby-Authorization"];
@@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
auth = httpReq.Request.Headers[HeaderNames.Authorization];
}
- return GetAuthorization(auth);
+ return GetAuthorization(auth.Count > 0 ? auth[0] : null);
}
/// <summary>
@@ -223,7 +223,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="httpReq">The HTTP req.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
- private Dictionary<string, string> GetAuthorizationDictionary(HttpRequest httpReq)
+ private Dictionary<string, string>? GetAuthorizationDictionary(HttpRequest httpReq)
{
var auth = httpReq.Headers["X-Emby-Authorization"];
@@ -232,7 +232,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
auth = httpReq.Headers[HeaderNames.Authorization];
}
- return GetAuthorization(auth);
+ return GetAuthorization(auth.Count > 0 ? auth[0] : null);
}
/// <summary>
@@ -240,43 +240,43 @@ namespace Emby.Server.Implementations.HttpServer.Security
/// </summary>
/// <param name="authorizationHeader">The authorization header.</param>
/// <returns>Dictionary{System.StringSystem.String}.</returns>
- private Dictionary<string, string> GetAuthorization(string authorizationHeader)
+ private Dictionary<string, string>? GetAuthorization(ReadOnlySpan<char> authorizationHeader)
{
if (authorizationHeader == null)
{
return null;
}
- var parts = authorizationHeader.Split(' ', 2);
+ var firstSpace = authorizationHeader.IndexOf(' ');
- // There should be at least to parts
- if (parts.Length != 2)
+ // There should be at least two parts
+ if (firstSpace == -1)
{
return null;
}
- var acceptedNames = new[] { "MediaBrowser", "Emby" };
+ var name = authorizationHeader[..firstSpace];
- // It has to be a digest request
- if (!acceptedNames.Contains(parts[0], StringComparer.OrdinalIgnoreCase))
+ if (!name.Equals("MediaBrowser", StringComparison.OrdinalIgnoreCase)
+ && !name.Equals("Emby", StringComparison.OrdinalIgnoreCase))
{
return null;
}
- // Remove uptil the first space
- authorizationHeader = parts[1];
- parts = authorizationHeader.Split(',');
+ authorizationHeader = authorizationHeader[(firstSpace + 1)..];
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- foreach (var item in parts)
+ foreach (var item in authorizationHeader.Split(','))
{
- var param = item.Trim().Split('=', 2);
+ var trimmedItem = item.Trim();
+ var firstEqualsSign = trimmedItem.IndexOf('=');
- if (param.Length == 2)
+ if (firstEqualsSign > 0)
{
- var value = NormalizeValue(param[1].Trim('"'));
- result[param[0]] = value;
+ var key = trimmedItem[..firstEqualsSign].ToString();
+ var value = NormalizeValue(trimmedItem[(firstEqualsSign + 1)..].Trim('"').ToString());
+ result[key] = value;
}
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
index dd77b45d8..c375f36ce 100644
--- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
@@ -36,14 +36,14 @@ namespace Emby.Server.Implementations.HttpServer.Security
return GetSession((HttpContext)requestContext);
}
- public User GetUser(HttpContext requestContext)
+ public User? GetUser(HttpContext requestContext)
{
var session = GetSession(requestContext);
return session == null || session.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(session.UserId);
}
- public User GetUser(object requestContext)
+ public User? GetUser(object requestContext)
{
return GetUser(((HttpRequest)requestContext).HttpContext);
}
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index 06acb5606..8f7d60669 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Buffers;
using System.IO.Pipelines;
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
index 1bee1ac31..861c0a95e 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index 7435e9d0b..47a83d77c 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index 3353fae9d..aa80bccd7 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 27096ed33..6a554e68a 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.IO
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
/// <exception cref="ArgumentNullException">filename</exception>
- public virtual string ResolveShortcut(string filename)
+ public virtual string? ResolveShortcut(string filename)
{
if (string.IsNullOrEmpty(filename))
{
@@ -601,7 +601,7 @@ namespace Emby.Server.Implementations.IO
return GetFiles(path, null, false, recursive);
}
- public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string> extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
{
var enumerationOptions = GetEnumerationOptions(recursive);
@@ -655,7 +655,7 @@ namespace Emby.Server.Implementations.IO
return GetFilePaths(path, null, false, recursive);
}
- public virtual IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
+ public virtual IEnumerable<string> GetFilePaths(string path, string[]? extensions, bool enableCaseSensitiveExtensions, bool recursive = false)
{
var enumerationOptions = GetEnumerationOptions(recursive);
diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
index e6696b8c4..76c58d5dc 100644
--- a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
+++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs
@@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.IO
public string Extension => ".mblink";
- public string Resolve(string shortcutPath)
+ public string? Resolve(string shortcutPath)
{
if (string.IsNullOrEmpty(shortcutPath))
{
diff --git a/Emby.Server.Implementations/IO/StreamHelper.cs b/Emby.Server.Implementations/IO/StreamHelper.cs
index c16ebd61b..e4f5f4cf0 100644
--- a/Emby.Server.Implementations/IO/StreamHelper.cs
+++ b/Emby.Server.Implementations/IO/StreamHelper.cs
@@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.IO
{
public class StreamHelper : IStreamHelper
{
- public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
+ public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action? onStarted, CancellationToken cancellationToken)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
try
diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs
index f719dc5f8..a430b9e72 100644
--- a/Emby.Server.Implementations/IStartupOptions.cs
+++ b/Emby.Server.Implementations/IStartupOptions.cs
@@ -1,5 +1,4 @@
#pragma warning disable CS1591
-#nullable enable
namespace Emby.Server.Implementations
{
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 6fa3c1c61..833fb0b7a 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
index 161b4c452..ff5f26ce0 100644
--- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Images/DynamicImageProvider.cs b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
index 50c531482..900b3fd9c 100644
--- a/Emby.Server.Implementations/Images/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Images/FolderImageProvider.cs b/Emby.Server.Implementations/Images/FolderImageProvider.cs
index 0224ab32a..859017f86 100644
--- a/Emby.Server.Implementations/Images/FolderImageProvider.cs
+++ b/Emby.Server.Implementations/Images/FolderImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs
index 381788231..6da431c68 100644
--- a/Emby.Server.Implementations/Images/GenreImageProvider.cs
+++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/Images/PlaylistImageProvider.cs b/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
index a4c106e87..b8f0f0d65 100644
--- a/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
+++ b/Emby.Server.Implementations/Images/PlaylistImageProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
index 236453e80..6c65b5899 100644
--- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
+++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs
index e30a67593..5384c04b3 100644
--- a/Emby.Server.Implementations/Library/IgnorePatterns.cs
+++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Linq;
using DotNet.Globbing;
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 4d207471a..f8d8197d4 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
index c2951dd15..4ef7923db 100644
--- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs
+++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 85d6d3043..38e81d14c 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
index 28fa06239..b833122ea 100644
--- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs
+++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index f8bae4fd1..06300adeb 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs
index 0de4edb7e..86b8039fa 100644
--- a/Emby.Server.Implementations/Library/PathExtensions.cs
+++ b/Emby.Server.Implementations/Library/PathExtensions.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Diagnostics.CodeAnalysis;
using MediaBrowser.Common.Providers;
diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs
index 1d9b44874..ac75e5d3a 100644
--- a/Emby.Server.Implementations/Library/ResolverHelper.cs
+++ b/Emby.Server.Implementations/Library/ResolverHelper.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.IO;
using System.Linq;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index 4ad84579d..e893d6335 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index bf32381eb..8e1eccb10 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 60f82806f..3d2ae95d2 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using System.Threading.Tasks;
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 6e688693b..a3dcdc944 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -165,13 +167,13 @@ namespace Emby.Server.Implementations.Library.Resolvers
protected void SetVideoType(Video video, VideoFileInfo videoInfo)
{
- var extension = Path.GetExtension(video.Path);
- video.VideoType = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
- VideoType.Iso :
- VideoType.VideoFile;
+ var extension = Path.GetExtension(video.Path.AsSpan());
+ video.VideoType = extension.Equals(".iso", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".img", StringComparison.OrdinalIgnoreCase)
+ ? VideoType.Iso
+ : VideoType.VideoFile;
- video.IsShortcut = string.Equals(extension, ".strm", StringComparison.OrdinalIgnoreCase);
+ video.IsShortcut = extension.Equals(".strm", StringComparison.OrdinalIgnoreCase);
video.IsPlaceHolder = videoInfo.IsStub;
if (videoInfo.IsStub)
@@ -193,11 +195,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
if (video.VideoType == VideoType.Iso)
{
- if (video.Path.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1)
+ if (video.Path.Contains("dvd", StringComparison.OrdinalIgnoreCase))
{
video.IsoType = IsoType.Dvd;
}
- else if (video.Path.IndexOf("bluray", StringComparison.OrdinalIgnoreCase) != -1)
+ else if (video.Path.Contains("bluray", StringComparison.OrdinalIgnoreCase))
{
video.IsoType = IsoType.BluRay;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
index 0525c7e30..68076730b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs
index 7dbce7a6e..7aaee017d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/FolderResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
diff --git a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
index 92fb2a753..fa45ccf84 100644
--- a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
index 295e9e120..69d71d0d9 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.IO;
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 16bf4dc4a..02c528764 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.IO;
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
index 204c8a62e..534bc80dd 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 3cb6542cf..57bf40e9e 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
index 5f051321f..ecd44be47 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
index 99f304190..7b4e14334 100644
--- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 6f29bc649..d6ae91056 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 768e2e4f5..7d707df18 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System.Globalization;
using Emby.Naming.TV;
using MediaBrowser.Controller.Entities.TV;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 8fc3e3e75..a1562abd3 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
index 62268fce9..9599faea4 100644
--- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index bcdf854ca..26e615fa0 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index 827e3c64b..667e46613 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index ac041bcf6..e2da672a3 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 7a6b1d8b6..3fcadf5b1 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 28a2095e1..797063120 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 9372b0f6c..26e4ef1ed 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs
index 8c27ca76e..0ec52a959 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EpgChannelData.cs
@@ -6,7 +6,6 @@ using MediaBrowser.Controller.LiveTv;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
-
internal class EpgChannelData
{
@@ -39,13 +38,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
- public ChannelInfo GetChannelById(string id)
+ public ChannelInfo? GetChannelById(string id)
=> _channelsById.GetValueOrDefault(id);
- public ChannelInfo GetChannelByNumber(string number)
+ public ChannelInfo? GetChannelByNumber(string number)
=> _channelsByNumber.GetValueOrDefault(number);
- public ChannelInfo GetChannelByName(string name)
+ public ChannelInfo? GetChannelByName(string name)
=> _channelsByName.GetValueOrDefault(name);
public static string NormalizeName(string value)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 1cac9cb96..bdab8c3e4 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 32245f899..108863869 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 1efa90e25..6c52a9a73 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 9af65cabb..00d02873c 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index 6824aa442..ebad4eddf 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 6af49dd45..21e1409ac 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 1145d8aa1..1f1628900 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index 3a738fd5d..ecd28097d 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index fbcd4ef37..00a37bb02 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs
index 740cbb66e..0f0453189 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/Channels.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
internal class Channels
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs
index 09d77f838..42068cd34 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index bbac6e055..c5700db71 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index a7fda1d72..3016eeda2 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index b16ccc561..50a2d9abb 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index f8baf55da..96a678c1d 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 4b170b2e4..69035dac9 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 84d416149..48a0c3cd3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index eeb2426f4..137ed27e2 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 220e423bf..dd5dee1d1 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index 031b5d2e7..8aaa1f7bb 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index 0781a0e33..137728616 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 4e25768cf..a8b18d292 100644
--- a/Emby.Server.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 2d1a559f1..9a1ca9946 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 14df20936..48281b75f 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -1,5 +1,3 @@
-#nullable enable
-
using System;
using System.Collections.Generic;
using System.Globalization;
diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
index 0259dc436..7cfd1fced 100644
--- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
+++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Concurrent;
using System.Globalization;
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 101d9b537..ccbd4289e 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
index af316e108..4f0df75bf 100644
--- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index 2312c85d9..baeb86a22 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -140,8 +140,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
previouslyFailedImages.Add(key);
var parentPath = Path.GetDirectoryName(failHistoryPath);
-
- Directory.CreateDirectory(parentPath);
+ if (parentPath != null)
+ {
+ Directory.CreateDirectory(parentPath);
+ }
string text = string.Join('|', previouslyFailedImages);
File.WriteAllText(failHistoryPath, text);
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
index 4abbf784b..50ba9bc89 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -75,4 +75,4 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
return Enumerable.Empty<TaskTriggerInfo>();
}
}
-} \ No newline at end of file
+}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index 3b40320ab..3b63536a4 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Model.Tasks;
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index b04fd7c7e..e13782fe0 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Linq;
using System.Threading;
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
index 7cd5493da..ced14195b 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index 0c0ebec08..a67f940b7 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Threading;
using MediaBrowser.Model.Tasks;
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 4bc12f44a..30823ab8f 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
@@ -297,50 +299,49 @@ namespace Emby.Server.Implementations.Security
AccessToken = reader[1].ToString()
};
- if (reader[2].SQLiteType != SQLiteType.Null)
- {
- info.DeviceId = reader[2].ToString();
- }
-
- if (reader[3].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(2, out var deviceId))
{
- info.AppName = reader[3].ToString();
+ info.DeviceId = deviceId;
}
- if (reader[4].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(3, out var appName))
{
- info.AppVersion = reader[4].ToString();
+ info.AppName = appName;
}
- if (reader[5].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(4, out var appVersion))
{
- info.DeviceName = reader[5].ToString();
+ info.AppVersion = appVersion;
}
- if (reader[6].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(6, out var userId))
{
- info.UserId = new Guid(reader[6].ToString());
+ info.UserId = new Guid(userId);
}
- if (reader[7].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(7, out var userName))
{
- info.UserName = reader[7].ToString();
+ info.UserName = userName;
}
info.DateCreated = reader[8].ReadDateTime();
- if (reader[9].SQLiteType != SQLiteType.Null)
+ if (reader.TryReadDateTime(9, out var dateLastActivity))
{
- info.DateLastActivity = reader[9].ReadDateTime();
+ info.DateLastActivity = dateLastActivity;
}
else
{
info.DateLastActivity = info.DateCreated;
}
- if (reader[10].SQLiteType != SQLiteType.Null)
+ if (reader.TryGetString(10, out var customName))
+ {
+ info.DeviceName = customName;
+ }
+ else if (reader.TryGetString(5, out var deviceName))
{
- info.DeviceName = reader[10].ToString();
+ info.DeviceName = deviceName;
}
return info;
@@ -361,9 +362,9 @@ namespace Emby.Server.Implementations.Security
foreach (var row in statement.ExecuteQuery())
{
- if (row[0].SQLiteType != SQLiteType.Null)
+ if (row.TryGetString(0, out var customName))
{
- result.CustomName = row[0].ToString();
+ result.CustomName = customName;
}
}
diff --git a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
index 27024e4e1..8d8b82f0a 100644
--- a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs
@@ -19,7 +19,9 @@ namespace Emby.Server.Implementations.Serialization
new ConcurrentDictionary<string, XmlSerializer>();
private static XmlSerializer GetSerializer(Type type)
- => _serializers.GetOrAdd(type.FullName, _ => new XmlSerializer(type));
+ => _serializers.GetOrAdd(
+ type.FullName ?? throw new ArgumentException($"Invalid type {type}."),
+ _ => new XmlSerializer(type));
/// <summary>
/// Serializes to writer.
@@ -38,7 +40,7 @@ namespace Emby.Server.Implementations.Serialization
/// <param name="type">The type.</param>
/// <param name="stream">The stream.</param>
/// <returns>System.Object.</returns>
- public object DeserializeFromStream(Type type, Stream stream)
+ public object? DeserializeFromStream(Type type, Stream stream)
{
using (var reader = XmlReader.Create(stream))
{
@@ -81,7 +83,7 @@ namespace Emby.Server.Implementations.Serialization
/// <param name="type">The type.</param>
/// <param name="file">The file.</param>
/// <returns>System.Object.</returns>
- public object DeserializeFromFile(Type type, string file)
+ public object? DeserializeFromFile(Type type, string file)
{
using (var stream = File.OpenRead(file))
{
@@ -95,7 +97,7 @@ namespace Emby.Server.Implementations.Serialization
/// <param name="type">The type.</param>
/// <param name="buffer">The buffer.</param>
/// <returns>System.Object.</returns>
- public object DeserializeFromBytes(Type type, byte[] buffer)
+ public object? DeserializeFromBytes(Type type, byte[] buffer)
{
using (var stream = new MemoryStream(buffer, 0, buffer.Length, false, true))
{
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 6844152ea..ef467da7e 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
index 39c369a01..e9e3ca7f4 100644
--- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs
index a653b58c2..ed1dfca59 100644
--- a/Emby.Server.Implementations/Session/WebSocketController.cs
+++ b/Emby.Server.Implementations/Session/WebSocketController.cs
@@ -1,6 +1,5 @@
#pragma warning disable CS1591
#pragma warning disable SA1600
-#nullable enable
using System;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
index 60698e803..2b0ab536f 100644
--- a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
if (x == null)
{
diff --git a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
index 7657cc74e..42e644970 100644
--- a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
@@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
}
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>System.String.</returns>
- private static string GetValue(BaseItem x)
+ private static string? GetValue(BaseItem? x)
{
var audio = x as IHasAlbumArtist;
diff --git a/Emby.Server.Implementations/Sorting/AlbumComparer.cs b/Emby.Server.Implementations/Sorting/AlbumComparer.cs
index 7dfdd9ecf..1db3f5e9c 100644
--- a/Emby.Server.Implementations/Sorting/AlbumComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AlbumComparer.cs
@@ -17,7 +17,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
}
@@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>System.String.</returns>
- private static string GetValue(BaseItem x)
+ private static string? GetValue(BaseItem? x)
{
var audio = x as Audio;
diff --git a/Emby.Server.Implementations/Sorting/ArtistComparer.cs b/Emby.Server.Implementations/Sorting/ArtistComparer.cs
index 756d3c5b6..98bee3fd9 100644
--- a/Emby.Server.Implementations/Sorting/ArtistComparer.cs
+++ b/Emby.Server.Implementations/Sorting/ArtistComparer.cs
@@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Sorting
public string Name => ItemSortBy.Artist;
/// <inheritdoc />
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase);
}
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>System.String.</returns>
- private static string GetValue(BaseItem x)
+ private static string? GetValue(BaseItem? x)
{
if (!(x is Audio audio))
{
diff --git a/Emby.Server.Implementations/Sorting/CommunityRatingComparer.cs b/Emby.Server.Implementations/Sorting/CommunityRatingComparer.cs
index 980954ba0..5f142fa4b 100644
--- a/Emby.Server.Implementations/Sorting/CommunityRatingComparer.cs
+++ b/Emby.Server.Implementations/Sorting/CommunityRatingComparer.cs
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
if (x == null)
{
diff --git a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
index fa136c36d..d20dedc2d 100644
--- a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
+++ b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
@@ -15,14 +15,14 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return GetValue(x).CompareTo(GetValue(y));
}
- private static float GetValue(BaseItem x)
+ private static float GetValue(BaseItem? x)
{
- return x.CriticRating ?? 0;
+ return x?.CriticRating ?? 0;
}
/// <summary>
diff --git a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
index cbca300d2..d3f10f78c 100644
--- a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
if (x == null)
{
diff --git a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
index 03ff19d21..b1cb123ce 100644
--- a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
@@ -1,3 +1,4 @@
+#nullable disable
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
index 16bd2aff8..08a44319f 100644
--- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
diff --git a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
index 0c4e82d01..73e628cf7 100644
--- a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
@@ -1,3 +1,4 @@
+#nullable disable
#pragma warning disable CS1591
using Jellyfin.Data.Entities;
diff --git a/Emby.Server.Implementations/Sorting/IsFolderComparer.cs b/Emby.Server.Implementations/Sorting/IsFolderComparer.cs
index a35192eff..3c5ddeefa 100644
--- a/Emby.Server.Implementations/Sorting/IsFolderComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsFolderComparer.cs
@@ -20,7 +20,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return GetValue(x).CompareTo(GetValue(y));
}
@@ -30,9 +30,9 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>System.String.</returns>
- private static int GetValue(BaseItem x)
+ private static int GetValue(BaseItem? x)
{
- return x.IsFolder ? 0 : 1;
+ return x?.IsFolder ?? true ? 0 : 1;
}
}
}
diff --git a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
index d95948406..7d77a8bc5 100644
--- a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using Jellyfin.Data.Entities;
diff --git a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
index 1632c5a7a..926835f90 100644
--- a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using Jellyfin.Data.Entities;
diff --git a/Emby.Server.Implementations/Sorting/NameComparer.cs b/Emby.Server.Implementations/Sorting/NameComparer.cs
index da020d8d8..4de81a69e 100644
--- a/Emby.Server.Implementations/Sorting/NameComparer.cs
+++ b/Emby.Server.Implementations/Sorting/NameComparer.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
if (x == null)
{
diff --git a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs
index 76bb798b5..a81f78ebf 100644
--- a/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs
+++ b/Emby.Server.Implementations/Sorting/OfficialRatingComparer.cs
@@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
if (x == null)
{
diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
index 5c2830322..04e4865cb 100644
--- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
+++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
diff --git a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
index 92ac04dc6..c98f97bf1 100644
--- a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
+++ b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return GetDate(x).CompareTo(GetDate(y));
}
@@ -26,8 +26,13 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>DateTime.</returns>
- private static DateTime GetDate(BaseItem x)
+ private static DateTime GetDate(BaseItem? x)
{
+ if (x == null)
+ {
+ return DateTime.MinValue;
+ }
+
if (x.PremiereDate.HasValue)
{
return x.PremiereDate.Value;
diff --git a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
index e2857df0b..df9f9957d 100644
--- a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
+++ b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
@@ -15,7 +15,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return GetValue(x).CompareTo(GetValue(y));
}
@@ -25,8 +25,13 @@ namespace Emby.Server.Implementations.Sorting
/// </summary>
/// <param name="x">The x.</param>
/// <returns>DateTime.</returns>
- private static int GetValue(BaseItem x)
+ private static int GetValue(BaseItem? x)
{
+ if (x == null)
+ {
+ return 0;
+ }
+
if (x.ProductionYear.HasValue)
{
return x.ProductionYear.Value;
diff --git a/Emby.Server.Implementations/Sorting/RandomComparer.cs b/Emby.Server.Implementations/Sorting/RandomComparer.cs
index 7739d0418..af3bc2750 100644
--- a/Emby.Server.Implementations/Sorting/RandomComparer.cs
+++ b/Emby.Server.Implementations/Sorting/RandomComparer.cs
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Sorting
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
- public int Compare(BaseItem x, BaseItem y)
+ public int Compare(BaseItem? x, BaseItem? y)
{
return Guid.NewGuid().CompareTo(Guid.NewGuid());
}
diff --git a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
index dde44333d..129315303 100644
--- a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
+++ b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs b/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs
index b9205ee07..4123a59f8 100644
--- a/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs
+++ b/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs
index f745e193b..8d30716d3 100644
--- a/Emby.Server.Implementations/Sorting/SortNameComparer.cs
+++ b/Emby.Server.Implementations/Sorting/SortNameComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/StartDateComparer.cs b/Emby.Server.Implementations/Sorting/StartDateComparer.cs
index 558a3d351..c3df7c47e 100644
--- a/Emby.Server.Implementations/Sorting/StartDateComparer.cs
+++ b/Emby.Server.Implementations/Sorting/StartDateComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Sorting/StudioComparer.cs b/Emby.Server.Implementations/Sorting/StudioComparer.cs
index 5766dc542..01445c525 100644
--- a/Emby.Server.Implementations/Sorting/StudioComparer.cs
+++ b/Emby.Server.Implementations/Sorting/StudioComparer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/SyncPlay/Group.cs b/Emby.Server.Implementations/SyncPlay/Group.cs
index 7c2ad2477..12efff261 100644
--- a/Emby.Server.Implementations/SyncPlay/Group.cs
+++ b/Emby.Server.Implementations/SyncPlay/Group.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
index 72c0a838e..993456196 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 829df64bf..a837f09ca 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#pragma warning disable CS1591
using System;
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index db5265e79..750f00168 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
using System;
using System.Net;
using System.Net.Sockets;
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 653b1381b..2351b7d8c 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -1,3 +1,5 @@
+#nullable disable
+
#nullable enable
using System;
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index b4154b361..555062e55 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -28,7 +28,6 @@ using MediaBrowser.Model.Net;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -545,7 +544,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
- var cancellationTokenSource = new CancellationTokenSource();
+ using var cancellationTokenSource = new CancellationTokenSource();
var streamingRequest = new VideoRequestDto
{
Id = itemId,
@@ -710,7 +709,7 @@ namespace Jellyfin.Api.Controllers
[FromQuery] EncodingContext? context,
[FromQuery] Dictionary<string, string> streamOptions)
{
- var cancellationTokenSource = new CancellationTokenSource();
+ using var cancellationTokenSource = new CancellationTokenSource();
var streamingRequest = new StreamingRequestDto
{
Id = itemId,
@@ -1138,7 +1137,7 @@ namespace Jellyfin.Api.Controllers
var isHlsInFmp4 = string.Equals(segmentContainer, "mp4", StringComparison.OrdinalIgnoreCase);
var hlsVersion = isHlsInFmp4 ? "7" : "3";
- var builder = new StringBuilder();
+ var builder = new StringBuilder(128);
builder.AppendLine("#EXTM3U")
.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
@@ -1191,7 +1190,7 @@ namespace Jellyfin.Api.Controllers
throw new ArgumentException("StartTimeTicks is not allowed.");
}
- var cancellationTokenSource = new CancellationTokenSource();
+ using var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
using var state = await StreamingHelpers.GetStreamingState(
@@ -1208,7 +1207,7 @@ namespace Jellyfin.Api.Controllers
_deviceManager,
_transcodingJobHelper,
TranscodingJobType,
- cancellationTokenSource.Token)
+ cancellationToken)
.ConfigureAwait(false);
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
@@ -1227,7 +1226,7 @@ namespace Jellyfin.Api.Controllers
}
var transcodingLock = _transcodingJobHelper.GetTranscodingLock(playlistPath);
- await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
+ await transcodingLock.WaitAsync(cancellationToken).ConfigureAwait(false);
var released = false;
var startTranscoding = false;
@@ -1323,24 +1322,28 @@ namespace Jellyfin.Api.Controllers
return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, segmentId, job, cancellationToken).ConfigureAwait(false);
}
- private double[] GetSegmentLengths(StreamState state)
- {
- var result = new List<double>();
-
- var ticks = state.RunTimeTicks ?? 0;
+ private static double[] GetSegmentLengths(StreamState state)
+ => GetSegmentLengthsInternal(state.RunTimeTicks ?? 0, state.SegmentLength);
- var segmentLengthTicks = TimeSpan.FromSeconds(state.SegmentLength).Ticks;
+ internal static double[] GetSegmentLengthsInternal(long runtimeTicks, int segmentlength)
+ {
+ var segmentLengthTicks = TimeSpan.FromSeconds(segmentlength).Ticks;
+ var wholeSegments = runtimeTicks / segmentLengthTicks;
+ var remainingTicks = runtimeTicks % segmentLengthTicks;
- while (ticks > 0)
+ var segmentsLen = wholeSegments + (remainingTicks == 0 ? 0 : 1);
+ var segments = new double[segmentsLen];
+ for (int i = 0; i < wholeSegments; i++)
{
- var length = ticks >= segmentLengthTicks ? segmentLengthTicks : ticks;
-
- result.Add(TimeSpan.FromTicks(length).TotalSeconds);
+ segments[i] = segmentlength;
+ }
- ticks -= length;
+ if (remainingTicks != 0)
+ {
+ segments[^1] = TimeSpan.FromTicks(remainingTicks).TotalSeconds;
}
- return result.ToArray();
+ return segments;
}
private string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding, int startNumber)
@@ -1376,18 +1379,13 @@ namespace Jellyfin.Api.Controllers
}
else if (string.Equals(segmentFormat, "mp4", StringComparison.OrdinalIgnoreCase))
{
- var outputFmp4HeaderArg = string.Empty;
- var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
- if (isWindows)
+ var outputFmp4HeaderArg = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) switch
{
// on Windows, the path of fmp4 header file needs to be configured
- outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"";
- }
- else
- {
+ true => " -hls_fmp4_init_filename \"" + outputPrefix + "-1" + outputExtension + "\"",
// on Linux/Unix, ffmpeg generate fmp4 header file to m3u8 output folder
- outputFmp4HeaderArg = " -hls_fmp4_init_filename \"" + outputFileNameWithoutExtension + "-1" + outputExtension + "\"";
- }
+ false => " -hls_fmp4_init_filename \"" + outputFileNameWithoutExtension + "-1" + outputExtension + "\""
+ };
segmentFormat = "fmp4" + outputFmp4HeaderArg;
}
@@ -1762,9 +1760,9 @@ namespace Jellyfin.Api.Controllers
private static FileSystemMetadata? GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
{
- var folder = Path.GetDirectoryName(playlist);
+ var folder = Path.GetDirectoryName(playlist) ?? throw new ArgumentException("Path can't be a root directory.", nameof(playlist));
- var filePrefix = Path.GetFileNameWithoutExtension(playlist) ?? string.Empty;
+ var filePrefix = Path.GetFileNameWithoutExtension(playlist);
try
{
diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
index 0879cbd18..b4db0c83e 100644
--- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
+++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs
@@ -22,7 +22,6 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.Helpers
@@ -380,7 +379,9 @@ namespace Jellyfin.Api.Helpers
/// <param name="outputFilePath">The output file path.</param>
private void DeleteHlsPartialStreamFiles(string outputFilePath)
{
- var directory = Path.GetDirectoryName(outputFilePath);
+ var directory = Path.GetDirectoryName(outputFilePath)
+ ?? throw new ArgumentException("Path can't be a root directory.", nameof(outputFilePath));
+
var name = Path.GetFileNameWithoutExtension(outputFilePath);
var filesToDelete = _fileSystem.GetFilePaths(directory)
diff --git a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
index e33e552ed..7b32d76ba 100644
--- a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
+++ b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
@@ -145,7 +145,8 @@ namespace Jellyfin.Api.Models.PlaybackDtos
var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
- var path = job.Path;
+ var path = job.Path ?? throw new ArgumentException("Path can't be null.");
+
var gapLengthInTicks = TimeSpan.FromSeconds(thresholdSeconds).Ticks;
if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
index a15a38177..96bd2ccc4 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
@@ -82,11 +82,14 @@ namespace Jellyfin.Server.Migrations.Routines
var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
- var config = File.Exists(Path.Combine(userDataDir, "config.xml"))
- ? (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), Path.Combine(userDataDir, "config.xml"))
+ var configPath = Path.Combine(userDataDir, "config.xml");
+ var config = File.Exists(configPath)
+ ? (UserConfiguration?)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), configPath) ?? new UserConfiguration()
: new UserConfiguration();
- var policy = File.Exists(Path.Combine(userDataDir, "policy.xml"))
- ? (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), Path.Combine(userDataDir, "policy.xml"))
+
+ var policyPath = Path.Combine(userDataDir, "policy.xml");
+ var policy = File.Exists(policyPath)
+ ? (UserPolicy?)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), policyPath) ?? new UserPolicy()
: new UserPolicy();
policy.AuthenticationProviderId = policy.AuthenticationProviderId?.Replace(
"Emby.Server.Implementations.Library",
diff --git a/Jellyfin.sln b/Jellyfin.sln
index 8626a4b1b..9fbd9d266 100644
--- a/Jellyfin.sln
+++ b/Jellyfin.sln
@@ -81,6 +81,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Tests", "te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Server.Integration.Tests", "tests\Jellyfin.Server.Integration.Tests\Jellyfin.Server.Integration.Tests.csproj", "{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Providers.Tests", "tests\Jellyfin.Providers.Tests\Jellyfin.Providers.Tests.csproj", "{A964008C-2136-4716-B6CB-B3426C22320A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -223,6 +225,10 @@ Global
{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A964008C-2136-4716-B6CB-B3426C22320A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A964008C-2136-4716-B6CB-B3426C22320A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A964008C-2136-4716-B6CB-B3426C22320A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A964008C-2136-4716-B6CB-B3426C22320A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -240,6 +246,7 @@ Global
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{3ADBCD8C-C0F2-4956-8FDC-35D686B74CF9} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{68B0B823-A5AC-4E8B-82EA-965AAC7BF76E} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {A964008C-2136-4716-B6CB-B3426C22320A} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
diff --git a/MediaBrowser.Common/Extensions/EnumerableExtensions.cs b/MediaBrowser.Common/Extensions/EnumerableExtensions.cs
new file mode 100644
index 000000000..2b8a6c395
--- /dev/null
+++ b/MediaBrowser.Common/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Common.Extensions
+{
+ /// <summary>
+ /// Static extensions for the <see cref="IEnumerable{T}"/> interface.
+ /// </summary>
+ public static class EnumerableExtensions
+ {
+ /// <summary>
+ /// Determines whether the value is contained in the source collection.
+ /// </summary>
+ /// <param name="source">An instance of the <see cref="IEnumerable{String}"/> interface.</param>
+ /// <param name="value">The value to look for in the collection.</param>
+ /// <param name="stringComparison">The string comparison.</param>
+ /// <returns>A value indicating whether the value is contained in the collection.</returns>
+ /// <exception cref="ArgumentNullException">The source is null.</exception>
+ public static bool Contains(this IEnumerable<string> source, ReadOnlySpan<char> value, StringComparison stringComparison)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (source is IList<string> list)
+ {
+ int len = list.Count;
+ for (int i = 0; i < len; i++)
+ {
+ if (value.Equals(list[i], stringComparison))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ foreach (string element in source)
+ {
+ if (value.Equals(element, stringComparison))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs
index 48bd9522a..1853896ee 100644
--- a/MediaBrowser.Controller/Extensions/StringExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 88de5b292..61f3bc771 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -4,59 +4,10 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Controller.MediaEncoding
{
- public class EncodingJobOptions : BaseEncodingJobOptions
- {
- public string OutputDirectory { get; set; }
-
- public string ItemId { get; set; }
-
- public string TempDirectory { get; set; }
-
- public bool ReadInputAtNativeFramerate { get; set; }
-
- /// <summary>
- /// Gets a value indicating whether this instance has fixed resolution.
- /// </summary>
- /// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value>
- public bool HasFixedResolution => Width.HasValue || Height.HasValue;
-
- public DeviceProfile DeviceProfile { get; set; }
-
- public EncodingJobOptions(StreamInfo info, DeviceProfile deviceProfile)
- {
- Container = info.Container;
- StartTimeTicks = info.StartPositionTicks;
- MaxWidth = info.MaxWidth;
- MaxHeight = info.MaxHeight;
- MaxFramerate = info.MaxFramerate;
- Id = info.ItemId;
- MediaSourceId = info.MediaSourceId;
- AudioCodec = info.TargetAudioCodec.FirstOrDefault();
- MaxAudioChannels = info.GlobalMaxAudioChannels;
- AudioBitRate = info.AudioBitrate;
- AudioSampleRate = info.TargetAudioSampleRate;
- DeviceProfile = deviceProfile;
- VideoCodec = info.TargetVideoCodec.FirstOrDefault();
- VideoBitRate = info.VideoBitrate;
- AudioStreamIndex = info.AudioStreamIndex;
- SubtitleMethod = info.SubtitleDeliveryMethod;
- Context = info.Context;
- TranscodingMaxAudioChannels = info.TranscodingMaxAudioChannels;
-
- if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
- {
- SubtitleStreamIndex = info.SubtitleStreamIndex;
- }
-
- StreamOptions = info.StreamOptions;
- }
- }
-
// For now until api and media encoding layers are unified
public class BaseEncodingJobOptions
{
diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs
index a60dc2ea1..6b896b41f 100644
--- a/MediaBrowser.Controller/Net/ISessionContext.cs
+++ b/MediaBrowser.Controller/Net/ISessionContext.cs
@@ -10,10 +10,10 @@ namespace MediaBrowser.Controller.Net
{
SessionInfo GetSession(object requestContext);
- User GetUser(object requestContext);
+ User? GetUser(object requestContext);
SessionInfo GetSession(HttpContext requestContext);
- User GetUser(HttpContext requestContext);
+ User? GetUser(HttpContext requestContext);
}
}
diff --git a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
index 727cbe639..07fe1ea8a 100644
--- a/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
+++ b/MediaBrowser.Controller/Sorting/IBaseItemComparer.cs
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Sorting
/// <summary>
/// Interface IBaseItemComparer.
/// </summary>
- public interface IBaseItemComparer : IComparer<BaseItem>
+ public interface IBaseItemComparer : IComparer<BaseItem?>
{
/// <summary>
/// Gets the name.
diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
index 7ad8c24e8..31475e22f 100644
--- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
@@ -466,7 +466,7 @@ namespace MediaBrowser.LocalMetadata.Images
return added;
}
- private bool AddImage(IEnumerable<FileSystemMetadata> files, List<LocalImageInfo> images, string name, ImageType type)
+ private bool AddImage(List<FileSystemMetadata> files, List<LocalImageInfo> images, string name, ImageType type)
{
var image = GetImage(files, name);
@@ -484,9 +484,20 @@ namespace MediaBrowser.LocalMetadata.Images
return false;
}
- private FileSystemMetadata? GetImage(IEnumerable<FileSystemMetadata> files, string name)
+ private static FileSystemMetadata? GetImage(IReadOnlyList<FileSystemMetadata> files, string name)
{
- return files.FirstOrDefault(i => !i.IsDirectory && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase) && i.Length > 0);
+ for (var i = 0; i < files.Count; i++)
+ {
+ var file = files[i];
+ if (!file.IsDirectory
+ && file.Length > 0
+ && Path.GetFileNameWithoutExtension(file.FullName.AsSpan()).Equals(name, StringComparison.OrdinalIgnoreCase))
+ {
+ return file;
+ }
+ }
+
+ return null;
}
}
}
diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs
index e5c26430a..be4f1e16b 100644
--- a/MediaBrowser.Model/IO/IFileSystem.cs
+++ b/MediaBrowser.Model/IO/IFileSystem.cs
@@ -1,4 +1,3 @@
-#nullable disable
#pragma warning disable CS1591
using System;
@@ -25,7 +24,7 @@ namespace MediaBrowser.Model.IO
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
- string ResolveShortcut(string filename);
+ string? ResolveShortcut(string filename);
/// <summary>
/// Creates the shortcut.
@@ -160,7 +159,7 @@ namespace MediaBrowser.Model.IO
/// <returns>All found files.</returns>
IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false);
- IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string> extensions, bool enableCaseSensitiveExtensions, bool recursive);
+ IEnumerable<FileSystemMetadata> GetFiles(string path, IReadOnlyList<string>? extensions, bool enableCaseSensitiveExtensions, bool recursive);
/// <summary>
/// Gets the file system entries.
@@ -186,7 +185,7 @@ namespace MediaBrowser.Model.IO
/// <returns>IEnumerable&lt;System.String&gt;.</returns>
IEnumerable<string> GetFilePaths(string path, bool recursive = false);
- IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive);
+ IEnumerable<string> GetFilePaths(string path, string[]? extensions, bool enableCaseSensitiveExtensions, bool recursive);
/// <summary>
/// Gets the file system entry paths.
diff --git a/MediaBrowser.Model/IO/IShortcutHandler.cs b/MediaBrowser.Model/IO/IShortcutHandler.cs
index 14d5c4b62..2c364a962 100644
--- a/MediaBrowser.Model/IO/IShortcutHandler.cs
+++ b/MediaBrowser.Model/IO/IShortcutHandler.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Model.IO
/// </summary>
/// <param name="shortcutPath">The shortcut path.</param>
/// <returns>System.String.</returns>
- string Resolve(string shortcutPath);
+ string? Resolve(string shortcutPath);
/// <summary>
/// Creates the specified shortcut path.
diff --git a/MediaBrowser.Model/IO/IStreamHelper.cs b/MediaBrowser.Model/IO/IStreamHelper.cs
index 0e09db16e..f900da556 100644
--- a/MediaBrowser.Model/IO/IStreamHelper.cs
+++ b/MediaBrowser.Model/IO/IStreamHelper.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Model.IO
{
public interface IStreamHelper
{
- Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken);
+ Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action? onStarted, CancellationToken cancellationToken);
Task CopyToAsync(Stream source, Stream destination, int bufferSize, int emptyReadLimit, CancellationToken cancellationToken);
diff --git a/MediaBrowser.Model/Tasks/ITaskTrigger.cs b/MediaBrowser.Model/Tasks/ITaskTrigger.cs
index cbd60cca1..db9fba696 100644
--- a/MediaBrowser.Model/Tasks/ITaskTrigger.cs
+++ b/MediaBrowser.Model/Tasks/ITaskTrigger.cs
@@ -11,7 +11,7 @@ namespace MediaBrowser.Model.Tasks
/// <summary>
/// Fires when the trigger condition is satisfied and the task should run.
/// </summary>
- event EventHandler<EventArgs> Triggered;
+ event EventHandler<EventArgs>? Triggered;
/// <summary>
/// Gets or sets the options of this task.
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
index e9f999c6d..b086ef07b 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
@@ -15,17 +15,6 @@ namespace MediaBrowser.Providers.MediaInfo
{
private readonly ILocalizationManager _localization;
- private static readonly HashSet<string> SubtitleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
- {
- ".srt",
- ".ssa",
- ".ass",
- ".sub",
- ".smi",
- ".sami",
- ".vtt"
- };
-
public SubtitleResolver(ILocalizationManager localization)
{
_localization = localization;
@@ -88,80 +77,65 @@ namespace MediaBrowser.Providers.MediaInfo
return list;
}
- private void AddExternalSubtitleStreams(
- List<MediaStream> streams,
- string folder,
- string videoPath,
- int startIndex,
- IDirectoryService directoryService,
- bool clearCache)
- {
- var files = directoryService.GetFilePaths(folder, clearCache).OrderBy(i => i).ToArray();
-
- AddExternalSubtitleStreams(streams, videoPath, startIndex, files);
- }
-
public void AddExternalSubtitleStreams(
List<MediaStream> streams,
string videoPath,
int startIndex,
string[] files)
{
- var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoPath);
- videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension);
+ var videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoPath);
foreach (var fullName in files)
{
- var extension = Path.GetExtension(fullName);
-
- if (!SubtitleExtensions.Contains(extension))
+ var extension = Path.GetExtension(fullName.AsSpan());
+ if (!IsSubtitleExtension(extension))
{
continue;
}
- var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
- fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension);
+ var fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fullName);
- if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) &&
- !fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- var codec = Path.GetExtension(fullName).ToLowerInvariant().TrimStart('.');
-
- if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
- {
- codec = "srt";
- }
+ MediaStream mediaStream;
- // If the subtitle file matches the video file name
- if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ // The subtitle filename must either be equal to the video filename or start with the video filename followed by a dot
+ if (videoFileNameWithoutExtension.Equals(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
{
- streams.Add(new MediaStream
+ mediaStream = new MediaStream
{
Index = startIndex++,
Type = MediaStreamType.Subtitle,
IsExternal = true,
- Path = fullName,
- Codec = codec
- });
+ Path = fullName
+ };
}
- else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
+ else if (fileNameWithoutExtension.Length > videoFileNameWithoutExtension.Length
+ && fileNameWithoutExtension[videoFileNameWithoutExtension.Length] == '.'
+ && fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
{
- var isForced = fullName.IndexOf(".forced.", StringComparison.OrdinalIgnoreCase) != -1 ||
- fullName.IndexOf(".foreign.", StringComparison.OrdinalIgnoreCase) != -1;
+ var isForced = fullName.Contains(".forced.", StringComparison.OrdinalIgnoreCase)
+ || fullName.Contains(".foreign.", StringComparison.OrdinalIgnoreCase);
- var isDefault = fullName.IndexOf(".default.", StringComparison.OrdinalIgnoreCase) != -1;
+ var isDefault = fullName.Contains(".default.", StringComparison.OrdinalIgnoreCase);
// Support xbmc naming conventions - 300.spanish.srt
- var language = fileNameWithoutExtension
- .Replace(".forced", string.Empty, StringComparison.OrdinalIgnoreCase)
- .Replace(".foreign", string.Empty, StringComparison.OrdinalIgnoreCase)
- .Replace(".default", string.Empty, StringComparison.OrdinalIgnoreCase)
- .Split('.')
- .LastOrDefault();
+ var languageSpan = fileNameWithoutExtension;
+ while (languageSpan.Length > 0)
+ {
+ var lastDot = languageSpan.LastIndexOf('.');
+ var currentSlice = languageSpan[lastDot..];
+ if (currentSlice.Equals(".default", StringComparison.OrdinalIgnoreCase)
+ || currentSlice.Equals(".forced", StringComparison.OrdinalIgnoreCase)
+ || currentSlice.Equals(".foreign", StringComparison.OrdinalIgnoreCase))
+ {
+ languageSpan = languageSpan[..lastDot];
+ continue;
+ }
+
+ languageSpan = languageSpan[(lastDot + 1)..];
+ break;
+ }
+ var language = languageSpan.ToString();
// Try to translate to three character code
// Be flexible and check against both the full and three character versions
var culture = _localization.FindLanguageInfo(language);
@@ -171,33 +145,58 @@ namespace MediaBrowser.Providers.MediaInfo
language = culture.ThreeLetterISOLanguageName;
}
- streams.Add(new MediaStream
+ mediaStream = new MediaStream
{
Index = startIndex++,
Type = MediaStreamType.Subtitle,
IsExternal = true,
Path = fullName,
- Codec = codec,
Language = language,
IsForced = isForced,
IsDefault = isDefault
- });
+ };
+ }
+ else
+ {
+ continue;
}
+
+ mediaStream.Codec = extension.TrimStart('.').ToString().ToLowerInvariant();
+
+ streams.Add(mediaStream);
}
}
- private string NormalizeFilenameForSubtitleComparison(string filename)
+ private static bool IsSubtitleExtension(ReadOnlySpan<char> extension)
+ {
+ return extension.Equals(".srt", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".ssa", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".ass", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".sub", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".vtt", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".smi", StringComparison.OrdinalIgnoreCase)
+ || extension.Equals(".sami", StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static ReadOnlySpan<char> NormalizeFilenameForSubtitleComparison(string filename)
{
// Try to account for sloppy file naming
filename = filename.Replace("_", string.Empty, StringComparison.Ordinal);
filename = filename.Replace(" ", string.Empty, StringComparison.Ordinal);
+ return Path.GetFileNameWithoutExtension(filename.AsSpan());
+ }
- // can't normalize this due to languages such as pt-br
- // filename = filename.Replace("-", string.Empty);
-
- // filename = filename.Replace(".", string.Empty);
+ private void AddExternalSubtitleStreams(
+ List<MediaStream> streams,
+ string folder,
+ string videoPath,
+ int startIndex,
+ IDirectoryService directoryService,
+ bool clearCache)
+ {
+ var files = directoryService.GetFilePaths(folder, clearCache).OrderBy(i => i).ToArray();
- return filename;
+ AddExternalSubtitleStreams(streams, videoPath, startIndex, files);
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
index bf42ceade..e4c908a62 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
@@ -1,6 +1,5 @@
#pragma warning disable CS1591
-using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -55,14 +54,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
return Enumerable.Empty<RemoteImageInfo>();
}
- var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
+ var language = item.GetPreferredMetadataLanguage();
+ var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), language, cancellationToken).ConfigureAwait(false);
if (personResult?.Images?.Profiles == null)
{
return Enumerable.Empty<RemoteImageInfo>();
}
var remoteImages = new RemoteImageInfo[personResult.Images.Profiles.Count];
- var language = item.GetPreferredMetadataLanguage();
for (var i = 0; i < personResult.Images.Profiles.Count; i++)
{
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
index 1757c8267..6db550b1d 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -32,7 +31,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
{
if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId))
{
- var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
+ var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
if (personResult != null)
{
@@ -96,7 +95,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
if (personTmdbId > 0)
{
- var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false);
+ var person = await _tmdbClientManager.GetPersonAsync(personTmdbId, id.MetadataLanguage, cancellationToken).ConfigureAwait(false);
result.HasMetadata = true;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 05e5d3ced..79ec6139d 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -276,11 +276,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// Gets a person eg. cast or crew member from the TMDb API based on its TMDb id.
/// </summary>
/// <param name="personTmdbId">The person's TMDb id.</param>
+ /// <param name="language">The episode's language.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The TMDb person information or null if not found.</returns>
- public async Task<Person> GetPersonAsync(int personTmdbId, CancellationToken cancellationToken)
+ public async Task<Person> GetPersonAsync(int personTmdbId, string language, CancellationToken cancellationToken)
{
- var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}";
+ var key = $"person-{personTmdbId.ToString(CultureInfo.InvariantCulture)}-{language}";
if (_memoryCache.TryGetValue(key, out Person person))
{
return person;
@@ -290,6 +291,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
person = await _tmDbClient.GetPersonAsync(
personTmdbId,
+ TmdbUtils.NormalizeLanguage(language),
PersonMethods.TvCredits | PersonMethods.MovieCredits | PersonMethods.Images | PersonMethods.ExternalIds,
cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
index b4e165f82..b713736a0 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
@@ -148,6 +148,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
if (parts.Length == 2)
{
+ // TMDB doesn't support Switzerland (de-CH, it-CH or fr-CH) so use the language (de, it or fr) without country code
+ if (string.Equals(parts[1], "CH", StringComparison.OrdinalIgnoreCase))
+ {
+ return parts[0];
+ }
+
language = parts[0] + "-" + parts[1].ToUpperInvariant();
}
diff --git a/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
new file mode 100644
index 000000000..117083815
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using AutoFixture;
+using AutoFixture.AutoMoq;
+using Jellyfin.Api.Controllers;
+using Jellyfin.Api.Helpers;
+using Jellyfin.Api.Models.StreamingDtos;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.MediaEncoding;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Controllers
+{
+ public class DynamicHlsControllerTests
+ {
+ [Theory]
+ [MemberData(nameof(GetSegmentLengths_Success_TestData))]
+ public void GetSegmentLengths_Success(long runtimeTicks, int segmentlength, double[] expected)
+ {
+ var res = DynamicHlsController.GetSegmentLengthsInternal(runtimeTicks, segmentlength);
+ Assert.Equal(expected.Length, res.Length);
+ for (int i = 0; i < expected.Length; i++)
+ {
+ Assert.Equal(expected[i], res[i]);
+ }
+ }
+
+ public static IEnumerable<object[]> GetSegmentLengths_Success_TestData()
+ {
+ yield return new object[] { 0, 6, Array.Empty<double>() };
+ yield return new object[]
+ {
+ TimeSpan.FromSeconds(3).Ticks,
+ 6,
+ new double[] { 3 }
+ };
+ yield return new object[]
+ {
+ TimeSpan.FromSeconds(6).Ticks,
+ 6,
+ new double[] { 6 }
+ };
+ yield return new object[]
+ {
+ TimeSpan.FromSeconds(3.3333333).Ticks,
+ 6,
+ new double[] { 3.3333333 }
+ };
+ yield return new object[]
+ {
+ TimeSpan.FromSeconds(9.3333333).Ticks,
+ 6,
+ new double[] { 6, 3.3333333 }
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs
index 9bbbe2970..c56046f03 100644
--- a/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs
@@ -148,7 +148,7 @@ namespace Jellyfin.Naming.Tests.Video
yield return new object[]
{
new VideoFileInfo(
- path: @"/server/Movies/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - Ozlem/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - Ozlem.mp4",
+ path: @"/server/Movies/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF.mp4",
container: "mp4",
name: "Rain Man",
year: 1988)
@@ -200,6 +200,10 @@ namespace Jellyfin.Naming.Tests.Video
Assert.NotNull(results[0]);
Assert.NotNull(results[1]);
Assert.Null(results[2]);
+ foreach (var result in results)
+ {
+ Assert.Null(result?.Container);
+ }
}
}
}
diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
new file mode 100644
index 000000000..b37515e78
--- /dev/null
+++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj
@@ -0,0 +1,37 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <IsPackable>false</IsPackable>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <Nullable>enable</Nullable>
+ <AnalysisMode>AllEnabledByDefault</AnalysisMode>
+ <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
+ <PackageReference Include="Moq" Version="4.16.1" />
+ <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ <PrivateAssets>all</PrivateAssets>
+ </PackageReference>
+ <PackageReference Include="coverlet.collector" Version="3.0.3">
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ <PrivateAssets>all</PrivateAssets>
+ </PackageReference>
+ </ItemGroup>
+
+ <!-- Code Analyzers -->
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs
new file mode 100644
index 000000000..b160e676e
--- /dev/null
+++ b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs
@@ -0,0 +1,96 @@
+#pragma warning disable CA1002 // Do not expose generic lists
+
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Providers.MediaInfo;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Providers.Tests.MediaInfo
+{
+ public class SubtitleResolverTests
+ {
+ public static IEnumerable<object[]> AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData()
+ {
+ var index = 0;
+ yield return new object[]
+ {
+ new List<MediaStream>(),
+ "/video/My.Video.mkv",
+ index,
+ new[]
+ {
+ "/video/My.Video.mp3",
+ "/video/My.Video.png",
+ "/video/My.Video.srt",
+ "/video/My.Video.txt",
+ "/video/My.Video.vtt",
+ "/video/My.Video.ass",
+ "/video/My.Video.sub",
+ "/video/My.Video.ssa",
+ "/video/My.Video.smi",
+ "/video/My.Video.sami",
+ "/video/My.Video.en.srt",
+ "/video/My.Video.default.en.srt",
+ "/video/My.Video.default.forced.en.srt",
+ "/video/My.Video.en.default.forced.srt",
+ "/video/My.Video.With.Additional.Garbage.en.srt",
+ "/video/My.Video With Additional Garbage.srt"
+ },
+ new[]
+ {
+ CreateMediaStream("/video/My.Video.srt", "srt", null, index++),
+ CreateMediaStream("/video/My.Video.vtt", "vtt", null, index++),
+ CreateMediaStream("/video/My.Video.ass", "ass", null, index++),
+ CreateMediaStream("/video/My.Video.sub", "sub", null, index++),
+ CreateMediaStream("/video/My.Video.ssa", "ssa", null, index++),
+ CreateMediaStream("/video/My.Video.smi", "smi", null, index++),
+ CreateMediaStream("/video/My.Video.sami", "sami", null, index++),
+ CreateMediaStream("/video/My.Video.en.srt", "srt", "en", index++),
+ CreateMediaStream("/video/My.Video.default.en.srt", "srt", "en", index++, isDefault: true),
+ CreateMediaStream("/video/My.Video.default.forced.en.srt", "srt", "en", index++, isForced: true, isDefault: true),
+ CreateMediaStream("/video/My.Video.en.default.forced.srt", "srt", "en", index++, isForced: true, isDefault: true),
+ CreateMediaStream("/video/My.Video.With.Additional.Garbage.en.srt", "srt", "en", index),
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData))]
+ public void AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles(List<MediaStream> streams, string videoPath, int startIndex, string[] files, MediaStream[] expectedResult)
+ {
+ new SubtitleResolver(Mock.Of<ILocalizationManager>()).AddExternalSubtitleStreams(streams, videoPath, startIndex, files);
+
+ Assert.Equal(expectedResult.Length, streams.Count);
+ for (var i = 0; i < expectedResult.Length; i++)
+ {
+ var expected = expectedResult[i];
+ var actual = streams[i];
+
+ Assert.Equal(expected.Index, actual.Index);
+ Assert.Equal(expected.Type, actual.Type);
+ Assert.Equal(expected.IsExternal, actual.IsExternal);
+ Assert.Equal(expected.Path, actual.Path);
+ Assert.Equal(expected.IsDefault, actual.IsDefault);
+ Assert.Equal(expected.IsForced, actual.IsForced);
+ Assert.Equal(expected.Language, actual.Language);
+ }
+ }
+
+ private static MediaStream CreateMediaStream(string path, string codec, string? language, int index, bool isForced = false, bool isDefault = false)
+ {
+ return new ()
+ {
+ Index = index,
+ Codec = codec,
+ Type = MediaStreamType.Subtitle,
+ IsExternal = true,
+ Path = path,
+ IsDefault = isDefault,
+ IsForced = isForced,
+ Language = language
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs
new file mode 100644
index 000000000..f6a7c676f
--- /dev/null
+++ b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsTests.cs
@@ -0,0 +1,27 @@
+using MediaBrowser.Providers.Plugins.Tmdb;
+using Xunit;
+
+namespace Jellyfin.Providers.Tests.Tmdb
+{
+ public static class TmdbUtilsTests
+ {
+ [Theory]
+ [InlineData("de", "de")]
+ [InlineData("En", "En")]
+ [InlineData("de-de", "de-DE")]
+ [InlineData("en-US", "en-US")]
+ [InlineData("de-CH", "de")]
+ public static void NormalizeLanguage_Valid_Success(string input, string expected)
+ {
+ Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input));
+ }
+
+ [Theory]
+ [InlineData(null, null)]
+ [InlineData("", "")]
+ public static void NormalizeLanguage_Invalid_Equal(string? input, string? expected)
+ {
+ Assert.Equal(expected, TmdbUtils.NormalizeLanguage(input!));
+ }
+ }
+}