Fix nullability errors in Jellyfin.Api (part 1)

This commit is contained in:
crobibero 2020-11-13 09:04:31 -07:00
parent e8675a6c24
commit 01355e0498
29 changed files with 155 additions and 54 deletions

View File

@ -1347,7 +1347,13 @@ namespace Jellyfin.Api.Controllers
var mapArgs = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty;
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer);
var directory = Path.GetDirectoryName(outputPath);
if (directory == null)
{
throw new NullReferenceException(nameof(directory));
}
var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer);
var segmentFormat = GetSegmentFileExtension(state.Request.SegmentContainer).TrimStart('.');
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
@ -1566,6 +1572,10 @@ namespace Jellyfin.Api.Controllers
private string GetSegmentPath(StreamState state, string playlist, int index)
{
var folder = Path.GetDirectoryName(playlist);
if (folder == null)
{
throw new NullReferenceException(nameof(folder));
}
var filename = Path.GetFileNameWithoutExtension(playlist);

View File

@ -103,6 +103,11 @@ namespace Jellyfin.Api.Controllers
if (validatePathDto.ValidateWritable)
{
if (validatePathDto.Path == null)
{
throw new NullReferenceException(nameof(validatePathDto.Path));
}
var file = Path.Combine(validatePathDto.Path, Guid.NewGuid().ToString());
try
{

View File

@ -177,7 +177,7 @@ namespace Jellyfin.Api.Controllers
return _dtoService.GetBaseItemDto(item, dtoOptions);
}
private T GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
where T : BaseItem, new()
{
var result = libraryManager.GetItemList(new InternalItemsQuery

View File

@ -136,6 +136,11 @@ namespace Jellyfin.Api.Controllers
string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase)
&& i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);
if (playlistPath == null)
{
throw new NullReferenceException(nameof(playlistPath));
}
return GetFileResult(file, playlistPath);
}

View File

@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers
/// <param name="theme">Theme to search.</param>
/// <param name="name">File name to search for.</param>
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
private ActionResult GetImageFile(string basePath, string? theme, string? name)
private ActionResult GetImageFile(string basePath, string theme, string? name)
{
var themeFolder = Path.Combine(basePath, theme);
if (Directory.Exists(themeFolder))

View File

@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Attributes;
@ -1268,7 +1269,7 @@ namespace Jellyfin.Api.Controllers
Response.Headers.Add(key, value);
}
Response.ContentType = imageContentType;
Response.ContentType = imageContentType ?? MediaTypeNames.Text.Plain;
Response.Headers.Add(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateImageModified).TotalSeconds).ToString(CultureInfo.InvariantCulture));
Response.Headers.Add(HeaderNames.Vary, HeaderNames.Accept);

View File

@ -334,10 +334,21 @@ namespace Jellyfin.Api.Controllers
private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath)
{
using var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
if (result.Content.Headers.ContentType?.MediaType == null)
{
throw new NullReferenceException(nameof(result.Content.Headers.ContentType));
}
var ext = result.Content.Headers.ContentType.MediaType.Split('/')[^1];
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
var directory = Path.GetDirectoryName(fullCachePath);
if (directory == null)
{
throw new NullReferenceException(nameof(directory));
}
Directory.CreateDirectory(directory);
using (var stream = result.Content)
{
await using var fileStream = new FileStream(
@ -351,7 +362,13 @@ namespace Jellyfin.Api.Controllers
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath);
if (pointerCacheDirectory == null)
{
throw new NullReferenceException(nameof(pointerCacheDirectory));
}
Directory.CreateDirectory(pointerCacheDirectory);
await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath).ConfigureAwait(false);
}

View File

@ -455,7 +455,7 @@ namespace Jellyfin.Api.Controllers
: null;
var dtoOptions = new DtoOptions().AddClientFields(Request);
BaseItem parent = item.GetParent();
BaseItem? parent = item.GetParent();
while (parent != null)
{
@ -466,7 +466,7 @@ namespace Jellyfin.Api.Controllers
baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
parent = parent.GetParent();
parent = parent?.GetParent();
}
return baseItemDtos;
@ -854,7 +854,7 @@ namespace Jellyfin.Api.Controllers
return _libraryManager.GetItemsResult(query).TotalRecordCount;
}
private BaseItem TranslateParentItem(BaseItem item, User user)
private BaseItem? TranslateParentItem(BaseItem item, User user)
{
return item.GetParent() is AggregateFolder
? _libraryManager.GetUserRootFolder().GetChildren(user, true)

View File

@ -1078,7 +1078,7 @@ namespace Jellyfin.Api.Controllers
var client = _httpClientFactory.CreateClient(NamedClient.Default);
// https://json.schedulesdirect.org/20141201/available/countries
// Can't dispose the response as it's required up the call chain.
var response = await client.GetAsync("https://json.schedulesdirect.org/20141201/available/countries")
var response = await client.GetAsync(new Uri("https://json.schedulesdirect.org/20141201/available/countries"))
.ConfigureAwait(false);
return File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), MediaTypeNames.Application.Json);

View File

@ -140,7 +140,7 @@ namespace Jellyfin.Api.Controllers
{
var dtoOptions = new DtoOptions().AddClientFields(Request);
MusicGenre item;
MusicGenre? item;
if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
{
@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers
return _dtoService.GetBaseItemDto(item, dtoOptions);
}
private T GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
where T : BaseItem, new()
{
var result = libraryManager.GetItemList(new InternalItemsQuery

View File

@ -54,6 +54,11 @@ namespace Jellyfin.Api.Controllers
string.IsNullOrEmpty(assemblyGuid) ? default : Guid.Parse(assemblyGuid))
.FirstOrDefault();
if (result == null)
{
return NotFound();
}
return result;
}

View File

@ -157,9 +157,9 @@ namespace Jellyfin.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public async Task<ActionResult> GetRemoteImage([FromQuery, Required] string imageUrl)
public async Task<ActionResult> GetRemoteImage([FromQuery, Required] Uri imageUrl)
{
var urlHash = imageUrl.GetMD5();
var urlHash = imageUrl.ToString().GetMD5();
var pointerCachePath = GetFullCachePath(urlHash.ToString());
string? contentPath = null;
@ -245,17 +245,35 @@ namespace Jellyfin.Api.Controllers
/// <param name="urlHash">The URL hash.</param>
/// <param name="pointerCachePath">The pointer cache path.</param>
/// <returns>Task.</returns>
private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath)
{
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
if (response.Content.Headers.ContentType?.MediaType == null)
{
throw new NullReferenceException(nameof(response.Content.Headers.ContentType));
}
var ext = response.Content.Headers.ContentType.MediaType.Split('/').Last();
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
var fullCacheDirectory = Path.GetDirectoryName(fullCachePath);
if (fullCacheDirectory == null)
{
throw new NullReferenceException(nameof(fullCacheDirectory));
}
Directory.CreateDirectory(fullCacheDirectory);
await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath);
if (pointerCacheDirectory == null)
{
throw new NullReferenceException(nameof(pointerCacheDirectory));
}
Directory.CreateDirectory(pointerCacheDirectory);
await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None)
.ConfigureAwait(false);
}

View File

@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers
}
}
private T GetParentWithImage<T>(BaseItem item, ImageType type)
private T? GetParentWithImage<T>(BaseItem item, ImageType type)
where T : BaseItem
{
return item.GetParents().OfType<T>().FirstOrDefault(i => i.HasImage(type));

View File

@ -361,7 +361,13 @@ namespace Jellyfin.Api.Controllers
var threads = _encodingHelper.GetNumberOfThreads(state, _encodingOptions, videoCodec);
var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions);
var format = !string.IsNullOrWhiteSpace(state.Request.SegmentContainer) ? "." + state.Request.SegmentContainer : ".ts";
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format;
var directory = Path.GetDirectoryName(outputPath);
if (directory == null)
{
throw new NullReferenceException(nameof(directory));
}
var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format;
var segmentFormat = format.TrimStart('.');
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))

View File

@ -1,4 +1,5 @@
using System.Net.Http;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Api.Models.StreamingDtos;
@ -98,6 +99,11 @@ namespace Jellyfin.Api.Helpers
TranscodingJobType transcodingJobType,
StreamingRequestDto streamingRequest)
{
if (_httpContextAccessor.HttpContext == null)
{
throw new NullReferenceException(nameof(_httpContextAccessor.HttpContext));
}
bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head;
var cancellationTokenSource = new CancellationTokenSource();

View File

@ -113,7 +113,7 @@ namespace Jellyfin.Api.Helpers
StreamingRequestDto streamingRequest,
bool enableAdaptiveBitrateStreaming)
{
var isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == WebRequestMethods.Http.Head;
var isHeadRequest = _httpContextAccessor.HttpContext?.Request.Method == WebRequestMethods.Http.Head;
var cancellationTokenSource = new CancellationTokenSource();
return await GetMasterPlaylistInternal(
streamingRequest,
@ -130,6 +130,11 @@ namespace Jellyfin.Api.Helpers
TranscodingJobType transcodingJobType,
CancellationTokenSource cancellationTokenSource)
{
if (_httpContextAccessor.HttpContext == null)
{
throw new NullReferenceException(nameof(_httpContextAccessor.HttpContext));
}
using var state = await StreamingHelpers.GetStreamingState(
streamingRequest,
_httpContextAccessor.HttpContext.Request,
@ -487,14 +492,14 @@ namespace Jellyfin.Api.Helpers
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
{
string profile = state.GetRequestedProfiles("h264").FirstOrDefault();
string? profile = state.GetRequestedProfiles("h264").FirstOrDefault();
return HlsCodecStringHelpers.GetH264String(profile, level);
}
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
{
string profile = state.GetRequestedProfiles("h265").FirstOrDefault();
string? profile = state.GetRequestedProfiles("h265").FirstOrDefault();
return HlsCodecStringHelpers.GetH265String(profile, level);
}

View File

@ -37,8 +37,8 @@ namespace Jellyfin.Api.Helpers
}
// Can't dispose the response as it's required up the call chain.
var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false);
var contentType = response.Content.Headers.ContentType.ToString();
var response = await httpClient.GetAsync(new Uri(state.MediaPath)).ConfigureAwait(false);
var contentType = response.Content.Headers.ContentType?.ToString();
httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none";

View File

@ -23,7 +23,7 @@ namespace Jellyfin.Api.Helpers
/// </summary>
/// <param name="profile">AAC profile.</param>
/// <returns>AAC codec string.</returns>
public static string GetAACString(string profile)
public static string GetAACString(string? profile)
{
StringBuilder result = new StringBuilder("mp4a", 9);
@ -46,7 +46,7 @@ namespace Jellyfin.Api.Helpers
/// <param name="profile">H.264 profile.</param>
/// <param name="level">H.264 level.</param>
/// <returns>H.264 string.</returns>
public static string GetH264String(string profile, int level)
public static string GetH264String(string? profile, int level)
{
StringBuilder result = new StringBuilder("avc1", 11);
@ -80,7 +80,7 @@ namespace Jellyfin.Api.Helpers
/// <param name="profile">H.265 profile.</param>
/// <param name="level">H.265 level.</param>
/// <returns>H.265 string.</returns>
public static string GetH265String(string profile, int level)
public static string GetH265String(string? profile, int level)
{
// The h265 syntax is a bit of a mystery at the time this comment was written.
// This is what I've found through various sources:

View File

@ -45,6 +45,10 @@ namespace Jellyfin.Api.Helpers
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync().ConfigureAwait(false);
if (line == null)
{
throw new NullReferenceException(nameof(line));
}
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
{

View File

@ -90,6 +90,11 @@ namespace Jellyfin.Api.Helpers
allowAsyncFileRead = true;
}
if (_path == null)
{
throw new NullReferenceException(nameof(_path));
}
await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions);
var eofCount = 0;

View File

@ -83,6 +83,10 @@ namespace Jellyfin.Api.Helpers
}
streamingRequest.StreamOptions = ParseStreamOptions(httpRequest.Query);
if (httpRequest.Path.Value == null)
{
throw new NullReferenceException(nameof(httpRequest.Path));
}
var url = httpRequest.Path.Value.Split('.').Last();

View File

@ -102,7 +102,7 @@ namespace Jellyfin.Api.Helpers
/// </summary>
/// <param name="playSessionId">Playback session id.</param>
/// <returns>The transcoding job.</returns>
public TranscodingJobDto GetTranscodingJob(string playSessionId)
public TranscodingJobDto? GetTranscodingJob(string playSessionId)
{
lock (_activeTranscodingJobs)
{
@ -116,7 +116,7 @@ namespace Jellyfin.Api.Helpers
/// <param name="path">Path to the transcoding file.</param>
/// <param name="type">The <see cref="TranscodingJobType"/>.</param>
/// <returns>The transcoding job.</returns>
public TranscodingJobDto GetTranscodingJob(string path, TranscodingJobType type)
public TranscodingJobDto? GetTranscodingJob(string path, TranscodingJobType type)
{
lock (_activeTranscodingJobs)
{
@ -193,9 +193,13 @@ namespace Jellyfin.Api.Helpers
/// Called when [transcode kill timer stopped].
/// </summary>
/// <param name="state">The state.</param>
private async void OnTranscodeKillTimerStopped(object state)
private async void OnTranscodeKillTimerStopped(object? state)
{
var job = (TranscodingJobDto)state;
var job = (TranscodingJobDto?)state;
if (job == null)
{
throw new NullReferenceException(nameof(job));
}
if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
{
@ -489,7 +493,13 @@ namespace Jellyfin.Api.Helpers
CancellationTokenSource cancellationTokenSource,
string? workingDirectory = null)
{
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
var directory = Path.GetDirectoryName(outputPath);
if (directory == null)
{
throw new NullReferenceException(nameof(directory));
}
Directory.CreateDirectory(directory);
await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
@ -523,7 +533,7 @@ namespace Jellyfin.Api.Helpers
RedirectStandardInput = true,
FileName = _mediaEncoder.EncoderPath,
Arguments = commandLineArguments,
WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory,
WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? string.Empty : workingDirectory,
ErrorDialog = false
},
EnableRaisingEvents = true
@ -827,7 +837,7 @@ namespace Jellyfin.Api.Helpers
{
lock (_transcodingLocks)
{
if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim result))
if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim? result))
{
result = new SemaphoreSlim(1, 1);
_transcodingLocks[outputPath] = result;
@ -837,7 +847,7 @@ namespace Jellyfin.Api.Helpers
}
}
private void OnPlaybackProgress(object sender, PlaybackProgressEventArgs e)
private void OnPlaybackProgress(object? sender, PlaybackProgressEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
{

View File

@ -196,7 +196,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
/// Start kill timer.
/// </summary>
/// <param name="callback">Callback action.</param>
public void StartKillTimer(Action<object> callback)
public void StartKillTimer(Action<object?> callback)
{
StartKillTimer(callback, PingTimeout);
}
@ -206,7 +206,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
/// </summary>
/// <param name="callback">Callback action.</param>
/// <param name="intervalMs">Callback interval.</param>
public void StartKillTimer(Action<object> callback, int intervalMs)
public void StartKillTimer(Action<object?> callback, int intervalMs)
{
if (HasExited)
{

View File

@ -101,7 +101,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
return _config.GetConfiguration<EncodingOptions>("encoding");
}
private async void TimerCallback(object state)
private async void TimerCallback(object? state)
{
if (_job.HasExited)
{

View File

@ -56,7 +56,7 @@ namespace Jellyfin.Api.WebSocketListeners
base.Dispose(dispose);
}
private void OnEntryCreated(object sender, GenericEventArgs<ActivityLogEntry> e)
private void OnEntryCreated(object? sender, GenericEventArgs<ActivityLogEntry> e)
{
SendData(true);
}

View File

@ -64,19 +64,19 @@ namespace Jellyfin.Api.WebSocketListeners
base.Dispose(dispose);
}
private void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
private void OnTaskCompleted(object? sender, TaskCompletionEventArgs e)
{
SendData(true);
e.Task.TaskProgress -= OnTaskProgress;
}
private void OnTaskExecuting(object sender, GenericEventArgs<IScheduledTaskWorker> e)
private void OnTaskExecuting(object? sender, GenericEventArgs<IScheduledTaskWorker> e)
{
SendData(true);
e.Argument.TaskProgress += OnTaskProgress;
}
private void OnTaskProgress(object sender, GenericEventArgs<double> e)
private void OnTaskProgress(object? sender, GenericEventArgs<double> e)
{
SendData(false);
}

View File

@ -66,37 +66,37 @@ namespace Jellyfin.Api.WebSocketListeners
base.Dispose(dispose);
}
private async void OnSessionManagerSessionActivity(object sender, SessionEventArgs e)
private async void OnSessionManagerSessionActivity(object? sender, SessionEventArgs e)
{
await SendData(false).ConfigureAwait(false);
}
private async void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e)
private async void OnSessionManagerCapabilitiesChanged(object? sender, SessionEventArgs e)
{
await SendData(true).ConfigureAwait(false);
}
private async void OnSessionManagerPlaybackProgress(object sender, PlaybackProgressEventArgs e)
private async void OnSessionManagerPlaybackProgress(object? sender, PlaybackProgressEventArgs e)
{
await SendData(!e.IsAutomated).ConfigureAwait(false);
}
private async void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e)
private async void OnSessionManagerPlaybackStopped(object? sender, PlaybackStopEventArgs e)
{
await SendData(true).ConfigureAwait(false);
}
private async void OnSessionManagerPlaybackStart(object sender, PlaybackProgressEventArgs e)
private async void OnSessionManagerPlaybackStart(object? sender, PlaybackProgressEventArgs e)
{
await SendData(true).ConfigureAwait(false);
}
private async void OnSessionManagerSessionEnded(object sender, SessionEventArgs e)
private async void OnSessionManagerSessionEnded(object? sender, SessionEventArgs e)
{
await SendData(true).ConfigureAwait(false);
}
private async void OnSessionManagerSessionStarted(object sender, SessionEventArgs e)
private async void OnSessionManagerSessionStarted(object? sender, SessionEventArgs e)
{
await SendData(true).ConfigureAwait(false);
}

View File

@ -758,7 +758,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
case MediaProtocol.Http:
{
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
.GetAsync(path, cancellationToken)
.GetAsync(new Uri(path), cancellationToken)
.ConfigureAwait(false);
return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
}

View File

@ -210,9 +210,9 @@ namespace MediaBrowser.Model.Net
return enableStreamDefault ? "application/octet-stream" : null;
}
public static string? ToExtension(string mimeType)
public static string? ToExtension(string? mimeType)
{
if (mimeType.Length == 0)
if (string.IsNullOrEmpty(mimeType))
{
throw new ArgumentException("String can't be empty.", nameof(mimeType));
}
@ -220,7 +220,7 @@ namespace MediaBrowser.Model.Net
// handle text/html; charset=UTF-8
mimeType = mimeType.Split(';')[0];
if (_extensionLookup.TryGetValue(mimeType, out string result))
if (_extensionLookup.TryGetValue(mimeType, out string? result))
{
return result;
}