aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers')
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs6
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs16
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj8
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioFileProber.cs5
-rw-r--r--MediaBrowser.Providers/MediaInfo/EmbeddedImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs2
-rw-r--r--MediaBrowser.Providers/Movies/ImdbExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs15
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs21
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs35
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs60
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs1
-rw-r--r--MediaBrowser.Providers/TV/Zap2ItExternalId.cs2
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs117
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayProvider.cs121
31 files changed, 368 insertions, 81 deletions
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index e7c2cd255..d82716831 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -263,7 +263,11 @@ namespace MediaBrowser.Providers.Manager
var fileStreamOptions = AsyncFile.WriteOptions;
fileStreamOptions.Mode = FileMode.Create;
- fileStreamOptions.PreallocationSize = source.Length;
+ if (source.CanSeek)
+ {
+ fileStreamOptions.PreallocationSize = source.Length;
+ }
+
var fs = new FileStream(path, fileStreamOptions);
await using (fs.ConfigureAwait(false))
{
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 75291b317..06445c90d 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -8,11 +8,11 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index f3211ba45..4ba884418 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -943,6 +943,12 @@ namespace MediaBrowser.Providers.Manager
/// <inheritdoc/>
public void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority)
{
+ ArgumentNullException.ThrowIfNull(itemId);
+ if (itemId.Equals(default))
+ {
+ throw new ArgumentException("Guid can't be empty", nameof(itemId));
+ }
+
if (_disposed)
{
return;
@@ -1090,13 +1096,13 @@ namespace MediaBrowser.Providers.Manager
return;
}
- if (!_disposeCancellationTokenSource.IsCancellationRequested)
- {
- _disposeCancellationTokenSource.Cancel();
- }
-
if (disposing)
{
+ if (!_disposeCancellationTokenSource.IsCancellationRequested)
+ {
+ _disposeCancellationTokenSource.Cancel();
+ }
+
_disposeCancellationTokenSource.Dispose();
}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 6a40833d7..8471f6fa1 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<!-- ProjectGuid is only included as a requirement for SonarQube analysis -->
<PropertyGroup>
@@ -33,8 +33,12 @@
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
- <!-- Code Analyzers-->
+ <!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <PackageReference Include="IDisposableAnalyzers">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
+ </PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
index 44f998742..d81704227 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
@@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.MediaInfo
_mediaSourceManager = mediaSourceManager;
}
- [GeneratedRegex("I:\\s+(.*?)\\s+LUFS")]
+ [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")]
private static partial Regex LUFSRegex();
/// <summary>
@@ -107,7 +107,6 @@ namespace MediaBrowser.Providers.MediaInfo
if (libraryOptions.EnableLUFSScan)
{
- string output;
using (var process = new Process()
{
StartInfo = new ProcessStartInfo
@@ -131,7 +130,7 @@ namespace MediaBrowser.Providers.MediaInfo
}
using var reader = process.StandardError;
- output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
+ var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
MatchCollection split = LUFSRegex().Matches(output);
diff --git a/MediaBrowser.Providers/MediaInfo/EmbeddedImageProvider.cs b/MediaBrowser.Providers/MediaInfo/EmbeddedImageProvider.cs
index c24f4e2fc..0bfee07fd 100644
--- a/MediaBrowser.Providers/MediaInfo/EmbeddedImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/EmbeddedImageProvider.cs
@@ -204,16 +204,10 @@ namespace MediaBrowser.Providers.MediaInfo
? Path.GetExtension(attachmentStream.FileName)
: MimeTypes.ToExtension(attachmentStream.MimeType);
- if (string.IsNullOrEmpty(extension))
- {
- extension = ".jpg";
- }
-
ImageFormat format = extension switch
{
".bmp" => ImageFormat.Bmp,
".gif" => ImageFormat.Gif,
- ".jpg" => ImageFormat.Jpg,
".png" => ImageFormat.Png,
".webp" => ImageFormat.Webp,
_ => ImageFormat.Jpg
diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
index f21939d2a..6eb75891a 100644
--- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
+++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs
@@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var query = new InternalItemsQuery
{
- MediaTypes = new string[] { MediaType.Video },
+ MediaTypes = new[] { MediaType.Video },
IsVirtualItem = false,
IncludeItemTypes = types,
DtoOptions = new DtoOptions(true),
diff --git a/MediaBrowser.Providers/Movies/ImdbExternalId.cs b/MediaBrowser.Providers/Movies/ImdbExternalId.cs
index d00f37db5..a8d74aa0b 100644
--- a/MediaBrowser.Providers/Movies/ImdbExternalId.cs
+++ b/MediaBrowser.Providers/Movies/ImdbExternalId.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
public ExternalIdMediaType? Type => null;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.imdb.com/title/{0}";
+ public string UrlFormatString => "https://www.imdb.com/title/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs b/MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs
index 1bb5e1ea8..8151ab471 100644
--- a/MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs
+++ b/MediaBrowser.Providers/Movies/ImdbPersonExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.imdb.com/name/{0}";
+ public string UrlFormatString => "https://www.imdb.com/name/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Person;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
index 3a400575b..138cfef19 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => null;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.theaudiodb.com/album/{0}";
+ public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicAlbum;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
index 55e2474a5..daad9706c 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
@@ -176,17 +176,12 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
Directory.CreateDirectory(Path.GetDirectoryName(path));
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
- var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- await using (stream.ConfigureAwait(false))
+ var fileStreamOptions = AsyncFile.WriteOptions;
+ fileStreamOptions.Mode = FileMode.Create;
+ var fs = new FileStream(path, fileStreamOptions);
+ await using (fs.ConfigureAwait(false))
{
- var fileStreamOptions = AsyncFile.WriteOptions;
- fileStreamOptions.Mode = FileMode.Create;
- fileStreamOptions.PreallocationSize = stream.Length;
- var xmlFileStream = new FileStream(path, fileStreamOptions);
- await using (xmlFileStream.ConfigureAwait(false))
- {
- await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
- }
+ await response.Content.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
index b9e57eb26..8aceb48c0 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
+ public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs
index f3385b3a9..92742b1aa 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs
@@ -154,20 +154,15 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
- var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- await using (stream.ConfigureAwait(false))
+ var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ var fileStreamOptions = AsyncFile.WriteOptions;
+ fileStreamOptions.Mode = FileMode.Create;
+ var xmlFileStream = new FileStream(path, fileStreamOptions);
+ await using (xmlFileStream.ConfigureAwait(false))
{
- var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- var fileStreamOptions = AsyncFile.WriteOptions;
- fileStreamOptions.Mode = FileMode.Create;
- fileStreamOptions.PreallocationSize = stream.Length;
- var xmlFileStream = new FileStream(path, fileStreamOptions);
- await using (xmlFileStream.ConfigureAwait(false))
- {
- await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
- }
+ await response.Content.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
index f8f6253ff..014481da2 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherAlbumExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.theaudiodb.com/album/{0}";
+ public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
index fd598c918..787539104 100644
--- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbOtherArtistExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc />
- public string? UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
+ public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
index f7850781e..825fe32fa 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumArtistExternalId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzAlbumArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
index a9d4472e7..b7d53984c 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumExternalId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzAlbumExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
index b89e67270..b3f001618 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistExternalId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
index fdaa5574f..a0a922293 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzOtherArtistExternalId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzOtherArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
index 0baab9955..47b6d6963 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzReleaseGroupExternalId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzReleaseGroupExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
index 5c974c411..cb4345660 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzTrackId.cs
@@ -20,7 +20,7 @@ public class MusicBrainzTrackId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Track;
/// <inheritdoc />
- public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}";
+ public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio;
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
index e4bb4eaea..e84f1359b 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs
@@ -8,6 +8,7 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading;
@@ -137,31 +138,27 @@ namespace MediaBrowser.Providers.Plugins.Omdb
var url = OmdbProvider.GetOmdbUrl(urlQuery.ToString());
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
- var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- await using (stream.ConfigureAwait(false))
+ if (isSearch)
{
- if (isSearch)
+ var searchResultList = await response.Content.ReadFromJsonAsync<SearchResultList>(_jsonOptions, cancellationToken).ConfigureAwait(false);
+ if (searchResultList?.Search is not null)
{
- var searchResultList = await JsonSerializer.DeserializeAsync<SearchResultList>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
- if (searchResultList?.Search is not null)
+ var resultCount = searchResultList.Search.Count;
+ var result = new RemoteSearchResult[resultCount];
+ for (var i = 0; i < resultCount; i++)
{
- var resultCount = searchResultList.Search.Count;
- var result = new RemoteSearchResult[resultCount];
- for (var i = 0; i < resultCount; i++)
- {
- result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
- }
-
- return result;
+ result[i] = ResultToMetadataResult(searchResultList.Search[i], searchInfo, indexNumberEnd);
}
+
+ return result;
}
- else
+ }
+ else
+ {
+ var result = await response.Content.ReadFromJsonAsync<SearchResult>(_jsonOptions, cancellationToken).ConfigureAwait(false);
+ if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
{
- var result = await JsonSerializer.DeserializeAsync<SearchResult>(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
- if (string.Equals(result?.Response, "true", StringComparison.OrdinalIgnoreCase))
- {
- return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
- }
+ return new[] { ResultToMetadataResult(result, searchInfo, indexNumberEnd) };
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
index 0e768bb83..d453a4ff4 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet;
/// <inheritdoc />
- public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
+ public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
index 38d2c5c69..6d6032e8f 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
@@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
/// <inheritdoc />
- public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
+ public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
index 027399aec..d26a70028 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc />
- public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
+ public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
index f18575aa9..489f5e2a1 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
@@ -13,6 +14,7 @@ using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using TMDbLib.Objects.TvShows;
namespace MediaBrowser.Providers.Plugins.Tmdb.TV
{
@@ -102,9 +104,61 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
return metadataResult;
}
- var episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
- .ConfigureAwait(false);
+ TvEpisode? episodeResult = null;
+ if (info.IndexNumberEnd.HasValue)
+ {
+ var startindex = episodeNumber;
+ var endindex = info.IndexNumberEnd;
+ List<TvEpisode>? result = null;
+ for (int? episode = startindex; episode <= endindex; episode++)
+ {
+ var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
+ if (episodeInfo is not null)
+ {
+ (result ??= new List<TvEpisode>()).Add(episodeInfo);
+ }
+ }
+
+ if (result is not null)
+ {
+ // Forces a deep copy of the first TvEpisode, so we don't modify the original because it's cached
+ episodeResult = new TvEpisode()
+ {
+ Name = result[0].Name,
+ Overview = result[0].Overview,
+ AirDate = result[0].AirDate,
+ VoteAverage = result[0].VoteAverage,
+ ExternalIds = result[0].ExternalIds,
+ Videos = result[0].Videos,
+ Credits = result[0].Credits
+ };
+
+ if (result.Count > 1)
+ {
+ var name = new StringBuilder(episodeResult.Name);
+ var overview = new StringBuilder(episodeResult.Overview);
+
+ for (int i = 1; i < result.Count; i++)
+ {
+ name.Append(" / ").Append(result[i].Name);
+ overview.Append(" / ").Append(result[i].Overview);
+ }
+
+ episodeResult.Name = name.ToString();
+ episodeResult.Overview = overview.ToString();
+ }
+ }
+ else
+ {
+ return metadataResult;
+ }
+ }
+ else
+ {
+ episodeResult = await _tmdbClientManager
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+ .ConfigureAwait(false);
+ }
if (episodeResult is null)
{
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
index df04cb2e7..5f2d7909a 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
@@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public ExternalIdMediaType? Type => ExternalIdMediaType.Series;
/// <inheritdoc />
- public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
+ public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item)
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 500ebaf71..72e59c9ac 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
diff --git a/MediaBrowser.Providers/TV/Zap2ItExternalId.cs b/MediaBrowser.Providers/TV/Zap2ItExternalId.cs
index 087e4036a..3cb18e424 100644
--- a/MediaBrowser.Providers/TV/Zap2ItExternalId.cs
+++ b/MediaBrowser.Providers/TV/Zap2ItExternalId.cs
@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.TV
public ExternalIdMediaType? Type => null;
/// <inheritdoc />
- public string? UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}";
+ public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}";
/// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Series;
diff --git a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
new file mode 100644
index 000000000..90c2ff8dd
--- /dev/null
+++ b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Trickplay;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace MediaBrowser.Providers.Trickplay;
+
+/// <summary>
+/// Class TrickplayImagesTask.
+/// </summary>
+public class TrickplayImagesTask : IScheduledTask
+{
+ private const int QueryPageLimit = 100;
+
+ private readonly ILogger<TrickplayImagesTask> _logger;
+ private readonly ILibraryManager _libraryManager;
+ private readonly ILocalizationManager _localization;
+ private readonly ITrickplayManager _trickplayManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TrickplayImagesTask"/> class.
+ /// </summary>
+ /// <param name="logger">The logger.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="localization">The localization manager.</param>
+ /// <param name="trickplayManager">The trickplay manager.</param>
+ public TrickplayImagesTask(
+ ILogger<TrickplayImagesTask> logger,
+ ILibraryManager libraryManager,
+ ILocalizationManager localization,
+ ITrickplayManager trickplayManager)
+ {
+ _libraryManager = libraryManager;
+ _logger = logger;
+ _localization = localization;
+ _trickplayManager = trickplayManager;
+ }
+
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskRefreshTrickplayImages");
+
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskRefreshTrickplayImagesDescription");
+
+ /// <inheritdoc />
+ public string Key => "RefreshTrickplayImages";
+
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
+
+ /// <inheritdoc />
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return new[]
+ {
+ new TaskTriggerInfo
+ {
+ Type = TaskTriggerInfo.TriggerDaily,
+ TimeOfDayTicks = TimeSpan.FromHours(3).Ticks
+ }
+ };
+ }
+
+ /// <inheritdoc />
+ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var query = new InternalItemsQuery
+ {
+ MediaTypes = new[] { MediaType.Video },
+ SourceTypes = new[] { SourceType.Library },
+ IsVirtualItem = false,
+ IsFolder = false,
+ Recursive = true,
+ Limit = QueryPageLimit
+ };
+
+ var numberOfVideos = _libraryManager.GetCount(query);
+
+ var startIndex = 0;
+ var numComplete = 0;
+
+ while (startIndex < numberOfVideos)
+ {
+ query.StartIndex = startIndex;
+ var videos = _libraryManager.GetItemList(query).OfType<Video>();
+
+ foreach (var video in videos)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ await _trickplayManager.RefreshTrickplayDataAsync(video, false, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error creating trickplay files for {ItemName}", video.Name);
+ }
+
+ numComplete++;
+ progress.Report(100d * numComplete / numberOfVideos);
+ }
+
+ startIndex += QueryPageLimit;
+ }
+
+ progress.Report(100);
+ }
+}
diff --git a/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs
new file mode 100644
index 000000000..f6dcde4f6
--- /dev/null
+++ b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs
@@ -0,0 +1,121 @@
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Trickplay;
+using MediaBrowser.Model.Configuration;
+
+namespace MediaBrowser.Providers.Trickplay;
+
+/// <summary>
+/// Class TrickplayProvider. Provides images and metadata for trickplay
+/// scrubbing previews.
+/// </summary>
+public class TrickplayProvider : ICustomMetadataProvider<Episode>,
+ ICustomMetadataProvider<MusicVideo>,
+ ICustomMetadataProvider<Movie>,
+ ICustomMetadataProvider<Trailer>,
+ ICustomMetadataProvider<Video>,
+ IHasItemChangeMonitor,
+ IHasOrder,
+ IForcedProvider
+{
+ private readonly IServerConfigurationManager _config;
+ private readonly ITrickplayManager _trickplayManager;
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TrickplayProvider"/> class.
+ /// </summary>
+ /// <param name="config">The configuration manager.</param>
+ /// <param name="trickplayManager">The trickplay manager.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ public TrickplayProvider(
+ IServerConfigurationManager config,
+ ITrickplayManager trickplayManager,
+ ILibraryManager libraryManager)
+ {
+ _config = config;
+ _trickplayManager = trickplayManager;
+ _libraryManager = libraryManager;
+ }
+
+ /// <inheritdoc />
+ public string Name => "Trickplay Provider";
+
+ /// <inheritdoc />
+ public int Order => 100;
+
+ /// <inheritdoc />
+ public bool HasChanged(BaseItem item, IDirectoryService directoryService)
+ {
+ if (item.IsFileProtocol)
+ {
+ var file = directoryService.GetFile(item.Path);
+ if (file is not null && item.DateModified != file.LastWriteTimeUtc)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Episode item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(MusicVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ private async Task<ItemUpdateType> FetchInternal(Video video, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ var libraryOptions = _libraryManager.GetLibraryOptions(video);
+ bool? enableDuringScan = libraryOptions?.ExtractTrickplayImagesDuringLibraryScan;
+ bool replace = options.ReplaceAllImages;
+
+ if (options.IsAutomated && !enableDuringScan.GetValueOrDefault(false))
+ {
+ return ItemUpdateType.None;
+ }
+
+ if (_config.Configuration.TrickplayOptions.ScanBehavior == TrickplayScanBehavior.Blocking)
+ {
+ await _trickplayManager.RefreshTrickplayDataAsync(video, replace, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ _ = _trickplayManager.RefreshTrickplayDataAsync(video, replace, cancellationToken).ConfigureAwait(false);
+ }
+
+ // The core doesn't need to trigger any save operations over this
+ return ItemUpdateType.None;
+ }
+}