aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
authorLogicalPhallacy <44458166+LogicalPhallacy@users.noreply.github.com>2019-10-28 21:54:40 -0700
committerGitHub <noreply@github.com>2019-10-28 21:54:40 -0700
commit8edb1c49d8d1835566bd30d8bf5460ab707b1ede (patch)
tree03c6b38523efcc4f29691cea3cdc4def0e8d26d8 /MediaBrowser.Controller
parent984e415c66cbd995d12ea95a3a9d3e2561ce4869 (diff)
parentc9f4a74af02e08b895cd6a8b8a408b1c0edfb6c4 (diff)
Merge pull request #6 from jellyfin/master
Bringing my branch up to sync
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Authentication/AuthenticationException.cs29
-rw-r--r--MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs3
-rw-r--r--MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs1
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs13
-rw-r--r--MediaBrowser.Controller/Drawing/IImageEncoder.cs21
-rw-r--r--MediaBrowser.Controller/Drawing/IImageProcessor.cs30
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs5
-rw-r--r--MediaBrowser.Controller/Dto/IDtoService.cs2
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs59
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs27
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs56
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs22
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs12
-rw-r--r--MediaBrowser.Controller/Entities/AudioBook.cs12
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs233
-rw-r--r--MediaBrowser.Controller/Entities/BasePluginFolder.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs10
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs15
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs9
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs57
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs10
-rw-r--r--MediaBrowser.Controller/Entities/IHasTrailers.cs70
-rw-r--r--MediaBrowser.Controller/Entities/ItemImageInfo.cs4
-rw-r--r--MediaBrowser.Controller/Entities/LinkedChild.cs9
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs22
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs13
-rw-r--r--MediaBrowser.Controller/Entities/MusicVideo.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs10
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs10
-rw-r--r--MediaBrowser.Controller/Entities/PhotoAlbum.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs10
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs43
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs24
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs24
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs4
-rw-r--r--MediaBrowser.Controller/Entities/User.cs87
-rw-r--r--MediaBrowser.Controller/Entities/UserItemData.cs4
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs10
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs10
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs36
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs8
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs10
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs5
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs4
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs30
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs41
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerInfo.cs6
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs924
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs6
-rw-r--r--MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs17
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs3
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs25
-rw-r--r--MediaBrowser.Controller/Providers/AlbumInfo.cs2
-rw-r--r--MediaBrowser.Controller/Providers/MetadataResult.cs3
-rw-r--r--MediaBrowser.Controller/Providers/MusicVideoInfo.cs4
-rw-r--r--MediaBrowser.Controller/Providers/SongInfo.cs7
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs4
61 files changed, 1201 insertions, 955 deletions
diff --git a/MediaBrowser.Controller/Authentication/AuthenticationException.cs b/MediaBrowser.Controller/Authentication/AuthenticationException.cs
new file mode 100644
index 000000000..62eca3ea9
--- /dev/null
+++ b/MediaBrowser.Controller/Authentication/AuthenticationException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace MediaBrowser.Controller.Authentication
+{
+ /// <summary>
+ /// The exception that is thrown when an attempt to authenticate fails.
+ /// </summary>
+ public class AuthenticationException : Exception
+ {
+ /// <inheritdoc />
+ public AuthenticationException() : base()
+ {
+
+ }
+
+ /// <inheritdoc />
+ public AuthenticationException(string message) : base(message)
+ {
+
+ }
+
+ /// <inheritdoc />
+ public AuthenticationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
index 2cf531eed..f5571065f 100644
--- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
@@ -9,10 +9,9 @@ namespace MediaBrowser.Controller.Authentication
string Name { get; }
bool IsEnabled { get; }
Task<ProviderAuthenticationResult> Authenticate(string username, string password);
- Task<bool> HasPassword(User user);
+ bool HasPassword(User user);
Task ChangePassword(User user, string newPassword);
void ChangeEasyPassword(User user, string newPassword, string newPasswordHash);
- string GetPasswordHash(User user);
string GetEasyPasswordHash(User user);
}
diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
index 9e5cd8816..2639960e7 100644
--- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Controller.Authentication
Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork);
Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
}
+
public class PasswordPinCreationResult
{
public string PinFile { get; set; }
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index adf03fb66..cdf2ca69e 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -1,10 +1,11 @@
using System;
+using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Channels
{
@@ -14,14 +15,14 @@ namespace MediaBrowser.Controller.Channels
{
if (user.Policy.BlockedChannels != null)
{
- if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.BlockedChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
}
else
{
- if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -30,10 +31,10 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override SourceType SourceType => SourceType.Channel;
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
@@ -60,7 +61,7 @@ namespace MediaBrowser.Controller.Channels
public static string GetInternalMetadataPath(string basePath, Guid id)
{
- return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata");
+ return System.IO.Path.Combine(basePath, "channels", id.ToString("N", CultureInfo.InvariantCulture), "metadata");
}
public override bool CanDelete()
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
index 4eaecd0a0..a0f9ae46e 100644
--- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs
+++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
@@ -18,16 +18,6 @@ namespace MediaBrowser.Controller.Drawing
IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; }
/// <summary>
- /// Encodes the image.
- /// </summary>
- string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
-
- /// <summary>
- /// Creates the image collage.
- /// </summary>
- /// <param name="options">The options.</param>
- void CreateImageCollage(ImageCollageOptions options);
- /// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
@@ -46,5 +36,16 @@ namespace MediaBrowser.Controller.Drawing
bool SupportsImageEncoding { get; }
ImageDimensions GetImageSize(string path);
+
+ /// <summary>
+ /// Encodes the image.
+ /// </summary>
+ string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
+
+ /// <summary>
+ /// Creates the image collage.
+ /// </summary>
+ /// <param name="options">The options.</param>
+ void CreateImageCollage(ImageCollageOptions options);
}
}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index a11e2186f..a58a11bd1 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -24,7 +24,15 @@ namespace MediaBrowser.Controller.Drawing
/// Gets the image enhancers.
/// </summary>
/// <value>The image enhancers.</value>
- IImageEnhancer[] ImageEnhancers { get; }
+ IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
+
+ /// <summary>
+ /// Gets a value indicating whether [supports image collage creation].
+ /// </summary>
+ /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
+ bool SupportsImageCollageCreation { get; }
+
+ IImageEncoder ImageEncoder { get; set; }
/// <summary>
/// Gets the dimensions of the image.
@@ -51,18 +59,12 @@ namespace MediaBrowser.Controller.Drawing
ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem);
/// <summary>
- /// Adds the parts.
- /// </summary>
- /// <param name="enhancers">The enhancers.</param>
- void AddParts(IEnumerable<IImageEnhancer> enhancers);
-
- /// <summary>
/// Gets the supported enhancers.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <returns>IEnumerable{IImageEnhancer}.</returns>
- IImageEnhancer[] GetSupportedEnhancers(BaseItem item, ImageType imageType);
+ IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType);
/// <summary>
/// Gets the image cache tag.
@@ -80,7 +82,7 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="image">The image.</param>
/// <param name="imageEnhancers">The image enhancers.</param>
/// <returns>Guid.</returns>
- string GetImageCacheTag(BaseItem item, ItemImageInfo image, IImageEnhancer[] imageEnhancers);
+ string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers);
/// <summary>
/// Processes the image.
@@ -109,7 +111,7 @@ namespace MediaBrowser.Controller.Drawing
/// <summary>
/// Gets the supported image output formats.
/// </summary>
- /// <returns>IReadOnlyCollection{ImageOutput}.</returns>
+ /// <returns><see cref="IReadOnlyCollection{ImageOutput}" />.</returns>
IReadOnlyCollection<ImageFormat> GetSupportedImageOutputFormats();
/// <summary>
@@ -118,14 +120,6 @@ namespace MediaBrowser.Controller.Drawing
/// <param name="options">The options.</param>
void CreateImageCollage(ImageCollageOptions options);
- /// <summary>
- /// Gets a value indicating whether [supports image collage creation].
- /// </summary>
- /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value>
- bool SupportsImageCollageCreation { get; }
-
- IImageEncoder ImageEncoder { get; set; }
-
bool SupportsTransparency(string path);
}
}
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index db432f500..29addf6e6 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Entities;
@@ -33,9 +34,9 @@ namespace MediaBrowser.Controller.Drawing
public int Quality { get; set; }
- public IImageEnhancer[] Enhancers { get; set; }
+ public IReadOnlyCollection<IImageEnhancer> Enhancers { get; set; }
- public ImageFormat[] SupportedOutputFormats { get; set; }
+ public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; }
public bool AddPlayedIndicator { get; set; }
diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs
index 4b6fd58fe..ba693a065 100644
--- a/MediaBrowser.Controller/Dto/IDtoService.cs
+++ b/MediaBrowser.Controller/Dto/IDtoService.cs
@@ -57,7 +57,7 @@ namespace MediaBrowser.Controller.Dto
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
- BaseItemDto[] GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
+ IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
/// <summary>
/// Gets the item by name dto.
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index 054df21e5..cacda8140 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -2,13 +2,13 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -23,7 +23,7 @@ namespace MediaBrowser.Controller.Entities
PhysicalLocationsList = Array.Empty<string>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPhysicalRoot => true;
public override bool CanDelete()
@@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
/// <summary>
@@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Entities
/// <value>The virtual children.</value>
public ConcurrentBag<BaseItem> VirtualChildren => _virtualChildren;
- [IgnoreDataMember]
+ [JsonIgnore]
public override string[] PhysicalLocations => PhysicalLocationsList;
public string[] PhysicalLocationsList { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 13a6fe44a..a700d0be4 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -19,15 +20,13 @@ namespace MediaBrowser.Controller.Entities.Audio
IHasLookupInfo<SongInfo>,
IHasMediaSources
{
- /// <summary>
- /// Gets or sets the artist.
- /// </summary>
- /// <value>The artist.</value>
- [IgnoreDataMember]
- public string[] Artists { get; set; }
+ /// <inheritdoc />
+ [JsonIgnore]
+ public IReadOnlyList<string> Artists { get; set; }
- [IgnoreDataMember]
- public string[] AlbumArtists { get; set; }
+ /// <inheritdoc />
+ [JsonIgnore]
+ public IReadOnlyList<string> AlbumArtists { get; set; }
public Audio()
{
@@ -40,22 +39,22 @@ namespace MediaBrowser.Controller.Entities.Audio
return 1;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool SupportsOwnedItems => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override Folder LatestItemsIndexContainer => AlbumEntity;
public override bool CanDownload()
@@ -63,38 +62,14 @@ namespace MediaBrowser.Controller.Entities.Audio
return IsFileProtocol;
}
- [IgnoreDataMember]
- public string[] AllArtists
- {
- get
- {
- var list = new string[AlbumArtists.Length + Artists.Length];
-
- var index = 0;
- foreach (var artist in AlbumArtists)
- {
- list[index] = artist;
- index++;
- }
- foreach (var artist in Artists)
- {
- list[index] = artist;
- index++;
- }
-
- return list;
-
- }
- }
-
- [IgnoreDataMember]
+ [JsonIgnore]
public MusicAlbum AlbumEntity => FindParent<MusicAlbum>();
/// <summary>
/// Gets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Audio;
/// <summary>
@@ -125,7 +100,7 @@ namespace MediaBrowser.Controller.Entities.Audio
songKey = Album + "-" + songKey;
}
- var albumArtist = AlbumArtists.Length == 0 ? null : AlbumArtists[0];
+ var albumArtist = AlbumArtists.FirstOrDefault();
if (!string.IsNullOrEmpty(albumArtist))
{
songKey = albumArtist + "-" + songKey;
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index a269b3486..056f31f78 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,14 +1,35 @@
+using System.Collections.Generic;
+
namespace MediaBrowser.Controller.Entities.Audio
{
public interface IHasAlbumArtist
{
- string[] AlbumArtists { get; set; }
+ IReadOnlyList<string> AlbumArtists { get; set; }
}
public interface IHasArtist
{
- string[] AllArtists { get; }
+ /// <summary>
+ /// Gets or sets the artists.
+ /// </summary>
+ /// <value>The artists.</value>
+ IReadOnlyList<string> Artists { get; set; }
+ }
+
+ public static class Extentions
+ {
+ public static IEnumerable<string> GetAllArtists<T>(this T item)
+ where T : IHasArtist, IHasAlbumArtist
+ {
+ foreach (var i in item.AlbumArtists)
+ {
+ yield return i;
+ }
- string[] Artists { get; set; }
+ foreach (var i in item.Artists)
+ {
+ yield return i;
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 5b2939b75..c216176e7 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
@@ -8,7 +9,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Audio
@@ -18,8 +18,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{
- public string[] AlbumArtists { get; set; }
- public string[] Artists { get; set; }
+ /// <inheritdoc />
+ public IReadOnlyList<string> AlbumArtists { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<string> Artists { get; set; }
public MusicAlbum()
{
@@ -27,13 +30,13 @@ namespace MediaBrowser.Controller.Entities.Audio
AlbumArtists = Array.Empty<string>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public MusicArtist MusicArtist => GetMusicArtist(new DtoOptions(true));
public MusicArtist GetMusicArtist(DtoOptions options)
@@ -41,8 +44,7 @@ namespace MediaBrowser.Controller.Entities.Audio
var parents = GetParents();
foreach (var parent in parents)
{
- var artist = parent as MusicArtist;
- if (artist != null)
+ if (parent is MusicArtist artist)
{
return artist;
}
@@ -56,46 +58,23 @@ namespace MediaBrowser.Controller.Entities.Audio
return null;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsCumulativeRunTimeTicks => true;
- [IgnoreDataMember]
- public string[] AllArtists
- {
- get
- {
- var list = new string[AlbumArtists.Length + Artists.Length];
-
- var index = 0;
- foreach (var artist in AlbumArtists)
- {
- list[index] = artist;
- index++;
- }
- foreach (var artist in Artists)
- {
- list[index] = artist;
- index++;
- }
-
- return list;
- }
- }
-
- [IgnoreDataMember]
- public string AlbumArtist => AlbumArtists.Length == 0 ? null : AlbumArtists[0];
+ [JsonIgnore]
+ public string AlbumArtist => AlbumArtists.FirstOrDefault();
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
/// <summary>
/// Gets the tracks.
/// </summary>
/// <value>The tracks.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
@@ -216,8 +195,7 @@ namespace MediaBrowser.Controller.Entities.Audio
private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
{
- var all = AllArtists;
- foreach (var i in all)
+ foreach (var i in this.GetAllArtists())
{
// This should not be necessary but we're seeing some cases of it
if (string.IsNullOrEmpty(i))
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 2d464bd32..efe0d3cf7 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
using Microsoft.Extensions.Logging;
@@ -18,25 +18,25 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicArtist : Folder, IItemByName, IHasMusicGenres, IHasDualAccess, IHasLookupInfo<ArtistInfo>
{
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsAccessedByName => ParentId.Equals(Guid.Empty);
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsFolder => !IsAccessedByName;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsCumulativeRunTimeTicks => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsDisplayedAsFolder => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -60,7 +60,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return LibraryManager.GetItemList(query);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override IEnumerable<BaseItem> Children
{
get
@@ -117,7 +117,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
/// <summary>
@@ -164,7 +164,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return info;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index d26aaf2bb..537e9630b 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.Audio
@@ -23,13 +23,13 @@ namespace MediaBrowser.Controller.Entities.Audio
return GetUserDataKeys()[0];
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsDisplayedAsFolder => true;
/// <summary>
@@ -37,7 +37,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return true;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs
index 65c8a5fdd..a13873bf9 100644
--- a/MediaBrowser.Controller/Entities/AudioBook.cs
+++ b/MediaBrowser.Controller/Entities/AudioBook.cs
@@ -1,23 +1,23 @@
using System;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class AudioBook : Audio.Audio, IHasSeries, IHasLookupInfo<SongInfo>
{
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPositionTicksResume => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesName { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid SeriesId { get; set; }
public string FindSeriesSortName()
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 10a603e42..599d41bb2 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -25,7 +26,6 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
using Microsoft.Extensions.Logging;
@@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Entities
/// The supported image extensions
/// </summary>
public static readonly string[] SupportedImageExtensions
- = new [] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" };
+ = new[] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" };
private static readonly List<string> _supportedExtensions = new List<string>(SupportedImageExtensions)
{
@@ -98,62 +98,62 @@ namespace MediaBrowser.Controller.Entities
SampleFolderName
};
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid[] ThemeSongIds { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid[] ThemeVideoIds { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string PreferredMetadataCountryCode { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string PreferredMetadataLanguage { get; set; }
public long? Size { get; set; }
public string Container { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string Tagline { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual ItemImageInfo[] ImageInfos { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsVirtualItem { get; set; }
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string Album { get; set; }
/// <summary>
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid ChannelId { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsAddingToPlaylist => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool AlwaysScanInternalMetadataPath => false;
/// <summary>
/// Gets a value indicating whether this instance is in mixed folder.
/// </summary>
/// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsInMixedFolder { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsPlayedStatus => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsPositionTicksResume => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsRemoteImageDownloading => true;
private string _name;
@@ -161,7 +161,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string Name
{
get => _name;
@@ -174,35 +174,35 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsUnaired => PremiereDate.HasValue && PremiereDate.Value.ToLocalTime().Date >= DateTime.Now.Date;
- [IgnoreDataMember]
+ [JsonIgnore]
public int? TotalBitrate { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public ExtraType? ExtraType { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsThemeMedia => ExtraType.HasValue && (ExtraType.Value == Model.Entities.ExtraType.ThemeSong || ExtraType.Value == Model.Entities.ExtraType.ThemeVideo);
- [IgnoreDataMember]
+ [JsonIgnore]
public string OriginalTitle { get; set; }
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid Id { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid OwnerId { get; set; }
/// <summary>
/// Gets or sets the audio.
/// </summary>
/// <value>The audio.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public ProgramAudio? Audio { get; set; }
/// <summary>
@@ -210,7 +210,7 @@ namespace MediaBrowser.Controller.Entities
/// Default is based on the type for everything except actual generic folders.
/// </summary>
/// <value>The display prefs id.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual Guid DisplayPreferencesId
{
get
@@ -224,10 +224,10 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string Path { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual SourceType SourceType
{
get
@@ -245,7 +245,7 @@ namespace MediaBrowser.Controller.Entities
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself
/// </summary>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string ContainingFolderPath
{
get
@@ -263,26 +263,26 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the name of the service.
/// </summary>
/// <value>The name of the service.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string ServiceName { get; set; }
/// <summary>
/// If this content came from an external service, the id of the content on that service
/// </summary>
- [IgnoreDataMember]
+ [JsonIgnore]
public string ExternalId { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string ExternalSeriesId { get; set; }
/// <summary>
/// Gets or sets the etag.
/// </summary>
/// <value>The etag.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string ExternalEtag { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsHidden => false;
public BaseItem GetOwner()
@@ -295,7 +295,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the type of the location.
/// </summary>
/// <value>The type of the location.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual LocationType LocationType
{
get
@@ -320,7 +320,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public MediaProtocol? PathProtocol
{
get
@@ -343,13 +343,13 @@ namespace MediaBrowser.Controller.Entities
return current.HasValue && current.Value == protocol;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsFileProtocol => IsPathProtocol(MediaProtocol.File);
- [IgnoreDataMember]
+ [JsonIgnore]
public bool HasPathProtocol => PathProtocol.HasValue;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsLocalMetadata
{
get
@@ -363,7 +363,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string FileNameWithoutExtension
{
get
@@ -377,7 +377,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool EnableAlphaNumericSorting => true;
private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
@@ -418,7 +418,7 @@ namespace MediaBrowser.Controller.Entities
/// This is just a helper for convenience
/// </summary>
/// <value>The primary image path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string PrimaryImagePath => this.GetImagePath(ImageType.Primary);
public bool IsMetadataFetcherEnabled(LibraryOptions libraryOptions, string name)
@@ -503,7 +503,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var folder in collectionFolders)
{
- if (allowed.Contains(folder.Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (allowed.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return true;
}
@@ -544,20 +544,20 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the date created.
/// </summary>
/// <value>The date created.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime DateCreated { get; set; }
/// <summary>
/// Gets or sets the date modified.
/// </summary>
/// <value>The date modified.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime DateModified { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime DateLastSaved { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime DateLastRefreshed { get; set; }
/// <summary>
@@ -583,24 +583,24 @@ namespace MediaBrowser.Controller.Entities
return Name;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsLocked { get; set; }
/// <summary>
/// Gets or sets the locked fields.
/// </summary>
/// <value>The locked fields.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public MetadataFields[] LockedFields { get; set; }
/// <summary>
/// Gets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string MediaType => null;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string[] PhysicalLocations
{
get
@@ -619,7 +619,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the name of the forced sort.
/// </summary>
/// <value>The name of the forced sort.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string ForcedSortName
{
get => _forcedSortName;
@@ -631,7 +631,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets the name of the sort.
/// </summary>
/// <value>The name of the sort.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string SortName
{
get
@@ -664,10 +664,10 @@ namespace MediaBrowser.Controller.Entities
{
if (SourceType == SourceType.Channel)
{
- return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N"), Id.ToString("N"));
+ return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
}
- var idString = Id.ToString("N");
+ var idString = Id.ToString("N", CultureInfo.InvariantCulture);
basePath = System.IO.Path.Combine(basePath, "library");
@@ -744,7 +744,7 @@ namespace MediaBrowser.Controller.Entities
return builder.ToString().RemoveDiacritics();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool EnableMediaSourceDisplay
{
get
@@ -758,14 +758,14 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid ParentId { get; set; }
/// <summary>
/// Gets or sets the parent.
/// </summary>
/// <value>The parent.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Folder Parent
{
get => GetParent() as Folder;
@@ -822,7 +822,7 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual Guid DisplayParentId
{
get
@@ -832,7 +832,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public BaseItem DisplayParent
{
get
@@ -850,97 +850,97 @@ namespace MediaBrowser.Controller.Entities
/// When the item first debuted. For movies this could be premiere date, episodes would be first aired
/// </summary>
/// <value>The premiere date.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime? PremiereDate { get; set; }
/// <summary>
/// Gets or sets the end date.
/// </summary>
/// <value>The end date.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime? EndDate { get; set; }
/// <summary>
/// Gets or sets the official rating.
/// </summary>
/// <value>The official rating.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string OfficialRating { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public int InheritedParentalRatingValue { get; set; }
/// <summary>
/// Gets or sets the critic rating.
/// </summary>
/// <value>The critic rating.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public float? CriticRating { get; set; }
/// <summary>
/// Gets or sets the custom rating.
/// </summary>
/// <value>The custom rating.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string CustomRating { get; set; }
/// <summary>
/// Gets or sets the overview.
/// </summary>
/// <value>The overview.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string Overview { get; set; }
/// <summary>
/// Gets or sets the studios.
/// </summary>
/// <value>The studios.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string[] Studios { get; set; }
/// <summary>
/// Gets or sets the genres.
/// </summary>
/// <value>The genres.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string[] Genres { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>The tags.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string[] Tags { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string[] ProductionLocations { get; set; }
/// <summary>
/// Gets or sets the home page URL.
/// </summary>
/// <value>The home page URL.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string HomePageUrl { get; set; }
/// <summary>
/// Gets or sets the community rating.
/// </summary>
/// <value>The community rating.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public float? CommunityRating { get; set; }
/// <summary>
/// Gets or sets the run time ticks.
/// </summary>
/// <value>The run time ticks.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public long? RunTimeTicks { get; set; }
/// <summary>
/// Gets or sets the production year.
/// </summary>
/// <value>The production year.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public int? ProductionYear { get; set; }
/// <summary>
@@ -948,20 +948,20 @@ namespace MediaBrowser.Controller.Entities
/// This could be episode number, album track number, etc.
/// </summary>
/// <value>The index number.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public int? IndexNumber { get; set; }
/// <summary>
/// For an episode this could be the season number, or for a song this could be the disc number.
/// </summary>
/// <value>The parent index number.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public int? ParentIndexNumber { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool HasLocalAlternateVersions => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public string OfficialRatingForComparison
{
get
@@ -982,7 +982,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public string CustomRatingForComparison
{
get
@@ -1095,7 +1095,7 @@ namespace MediaBrowser.Controller.Entities
var info = new MediaSourceInfo
{
- Id = item.Id.ToString("N"),
+ Id = item.Id.ToString("N", CultureInfo.InvariantCulture),
Protocol = protocol ?? MediaProtocol.File,
MediaStreams = MediaSourceManager.GetMediaStreams(item.Id),
Name = GetMediaSourceName(item),
@@ -1113,7 +1113,7 @@ namespace MediaBrowser.Controller.Entities
if (info.Protocol == MediaProtocol.File)
{
- info.ETag = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N");
+ info.ETag = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
var video = item as Video;
@@ -1407,13 +1407,13 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected virtual bool SupportsOwnedItems => !ParentId.Equals(Guid.Empty) && IsFileProtocol;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsPeople => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsThemeMedia => false;
/// <summary>
@@ -1613,10 +1613,10 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the provider ids.
/// </summary>
/// <value>The provider ids.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Dictionary<string, string> ProviderIds { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual Folder LatestItemsIndexContainer => null;
public virtual double GetDefaultPrimaryImageAspectRatio()
@@ -1626,10 +1626,10 @@ namespace MediaBrowser.Controller.Entities
public virtual string CreatePresentationUniqueKey()
{
- return Id.ToString("N");
+ return Id.ToString("N", CultureInfo.InvariantCulture);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public string PresentationUniqueKey { get; set; }
public string GetPresentationUniqueKey()
@@ -1934,7 +1934,7 @@ namespace MediaBrowser.Controller.Entities
return IsVisibleStandaloneInternal(user, true);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsInheritedParentImages => false;
protected bool IsVisibleStandaloneInternal(User user, bool checkFolders)
@@ -1977,10 +1977,10 @@ namespace MediaBrowser.Controller.Entities
/// Gets a value indicating whether this instance is folder.
/// </summary>
/// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsFolder => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsDisplayedAsFolder => false;
public virtual string GetClientTypeName()
@@ -2045,7 +2045,7 @@ namespace MediaBrowser.Controller.Entities
if (itemByPath == null)
{
- //Logger.LogWarning("Unable to find linked item at path {0}", info.Path);
+ Logger.LogWarning("Unable to find linked item at path {0}", info.Path);
}
return itemByPath;
@@ -2057,7 +2057,7 @@ namespace MediaBrowser.Controller.Entities
if (item == null)
{
- //Logger.LogWarning("Unable to find linked item at path {0}", info.Path);
+ Logger.LogWarning("Unable to find linked item at path {0}", info.Path);
}
return item;
@@ -2066,7 +2066,7 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool EnableRememberingTrackSelections => true;
/// <summary>
@@ -2085,14 +2085,17 @@ namespace MediaBrowser.Controller.Entities
if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
{
- if (current.Length == 0)
+ int curLen = current.Length;
+ if (curLen == 0)
{
Studios = new[] { name };
}
else
{
- var list =
- Studios = current.Concat(new[] { name }).ToArray();
+ var newArr = new string[curLen + 1];
+ current.CopyTo(newArr, 0);
+ newArr[curLen] = name;
+ Studios = newArr;
}
}
}
@@ -2231,8 +2234,12 @@ namespace MediaBrowser.Controller.Entities
else
{
- var currentCount = ImageInfos.Length;
- ImageInfos = ImageInfos.Concat(new[] { image }).ToArray();
+ var current = ImageInfos;
+ var currentCount = current.Length;
+ var newArr = new ItemImageInfo[currentCount + 1];
+ current.CopyTo(newArr, 0);
+ newArr[currentCount] = image;
+ ImageInfos = newArr;
}
}
@@ -2736,7 +2743,7 @@ namespace MediaBrowser.Controller.Entities
{
var list = GetEtagValues(user);
- return string.Join("|", list.ToArray()).GetMD5().ToString("N");
+ return string.Join("|", list.ToArray()).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
protected virtual List<string> GetEtagValues(User user)
@@ -2769,7 +2776,7 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsTopParent
{
get
@@ -2797,10 +2804,10 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsAncestors => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool StopRefreshIfLocalMetadataFound => true;
public virtual IEnumerable<Guid> GetIdsForAncestorQuery()
@@ -2871,16 +2878,24 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- public MediaUrl[] RemoteTrailers { get; set; }
+ public IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
public IEnumerable<BaseItem> GetExtras()
{
return ExtraIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName);
}
- public IEnumerable<BaseItem> GetExtras(ExtraType[] extraTypes)
+ public IEnumerable<BaseItem> GetExtras(IReadOnlyCollection<ExtraType> extraTypes)
{
- return ExtraIds.Select(LibraryManager.GetItemById).Where(i => i != null && extraTypes.Contains(i.ExtraType.Value)).OrderBy(i => i.SortName);
+ return ExtraIds.Select(LibraryManager.GetItemById).Where(i => i != null && extraTypes.Contains(i.ExtraType.Value));
+ }
+
+ public IEnumerable<BaseItem> GetTrailers()
+ {
+ if (this is IHasTrailers)
+ return ((IHasTrailers)this).LocalTrailerIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName);
+ else
+ return Array.Empty<BaseItem>();
}
public IEnumerable<BaseItem> GetDisplayExtras()
@@ -2900,7 +2915,7 @@ namespace MediaBrowser.Controller.Entities
}
// Possible types of extra videos
- public static ExtraType[] DisplayExtraTypes = new[] { Model.Entities.ExtraType.BehindTheScenes, Model.Entities.ExtraType.Clip, Model.Entities.ExtraType.DeletedScene, Model.Entities.ExtraType.Interview, Model.Entities.ExtraType.Sample, Model.Entities.ExtraType.Scene };
+ public static readonly IReadOnlyCollection<ExtraType> DisplayExtraTypes = new[] { Model.Entities.ExtraType.BehindTheScenes, Model.Entities.ExtraType.Clip, Model.Entities.ExtraType.DeletedScene, Model.Entities.ExtraType.Interview, Model.Entities.ExtraType.Sample, Model.Entities.ExtraType.Scene };
public virtual bool SupportsExternalTransfer => false;
}
diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
index 8cdb9695c..62d172fcc 100644
--- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs
+++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Model.Serialization;
+using System.Text.Json.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public abstract class BasePluginFolder : Folder, ICollectionFolder
{
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual string CollectionType => null;
public override bool CanDelete()
@@ -21,10 +21,10 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
//public override double? GetDefaultPrimaryImageAspectRatio()
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 7a23d9a66..44c35374d 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -1,21 +1,21 @@
using System;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Book;
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesName { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid SeriesId { get; set; }
public string FindSeriesSortName()
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 275052d48..bc5e7467e 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -2,14 +2,13 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
-
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -33,10 +32,10 @@ namespace MediaBrowser.Controller.Entities
PhysicalFolderIds = Array.Empty<Guid>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
public override bool CanDelete()
@@ -144,10 +143,10 @@ namespace MediaBrowser.Controller.Entities
/// Allow different display preferences for each collection folder
/// </summary>
/// <value>The display prefs id.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override Guid DisplayPreferencesId => Id;
- [IgnoreDataMember]
+ [JsonIgnore]
public override string[] PhysicalLocations => PhysicalLocationsList;
public override bool IsSaveLocalMetadataEnabled()
@@ -311,7 +310,7 @@ namespace MediaBrowser.Controller.Entities
/// Our children are actually just references to the ones in the physical root...
/// </summary>
/// <value>The actual children.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override IEnumerable<BaseItem> Children => GetActualChildren();
public IEnumerable<BaseItem> GetActualChildren()
@@ -361,7 +360,7 @@ namespace MediaBrowser.Controller.Entities
return result;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index f3bddd29c..d2ca11740 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@@ -28,13 +29,17 @@ namespace MediaBrowser.Controller.Entities
Url = url
};
- if (item.RemoteTrailers.Length == 0)
+ if (item.RemoteTrailers.Count == 0)
{
item.RemoteTrailers = new[] { mediaUrl };
}
else
{
- item.RemoteTrailers = item.RemoteTrailers.Concat(new[] { mediaUrl }).ToArray();
+ var oldIds = item.RemoteTrailers;
+ var newIds = new MediaUrl[oldIds.Count + 1];
+ oldIds.CopyTo(newIds);
+ newIds[oldIds.Count] = mediaUrl;
+ item.RemoteTrailers = newIds;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index c056bc0b4..61cc208d7 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Progress;
@@ -17,7 +19,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -38,7 +39,7 @@ namespace MediaBrowser.Controller.Entities
public LinkedChild[] LinkedChildren { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime? DateLastMediaAdded { get; set; }
public Folder()
@@ -46,35 +47,35 @@ namespace MediaBrowser.Controller.Entities
LinkedChildren = Array.Empty<LinkedChild>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsThemeMedia => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsPreSorted => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool IsPhysicalRoot => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => true;
/// <summary>
/// Gets a value indicating whether this instance is folder.
/// </summary>
/// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsFolder => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsDisplayedAsFolder => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsCumulativeRunTimeTicks => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsDateLastMediaAdded => false;
public override bool CanDelete()
@@ -99,7 +100,7 @@ namespace MediaBrowser.Controller.Entities
return baseResult;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override string FileNameWithoutExtension
{
get
@@ -126,7 +127,7 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected virtual bool SupportsShortcutChildren => false;
/// <summary>
@@ -161,14 +162,14 @@ namespace MediaBrowser.Controller.Entities
/// Gets the actual children.
/// </summary>
/// <value>The actual children.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual IEnumerable<BaseItem> Children => LoadChildren();
/// <summary>
/// thread-safe access to all recursive children of this folder - without regard to user
/// </summary>
/// <value>The recursive children.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public IEnumerable<BaseItem> RecursiveChildren => GetRecursiveChildren();
public override bool IsVisible(User user)
@@ -177,7 +178,7 @@ namespace MediaBrowser.Controller.Entities
{
if (user.Policy.BlockedMediaFolders != null)
{
- if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
+ if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) ||
// Backwards compatibility
user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
@@ -187,7 +188,7 @@ namespace MediaBrowser.Controller.Entities
}
else
{
- if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -665,36 +666,36 @@ namespace MediaBrowser.Controller.Entities
query.StartIndex = null;
query.Limit = null;
- var itemsList = LibraryManager.GetItemList(query);
+ IEnumerable<BaseItem> itemsList = LibraryManager.GetItemList(query);
var user = query.User;
if (user != null)
{
// needed for boxsets
- itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User)).ToList();
+ itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User));
}
- BaseItem[] returnItems;
+ IEnumerable<BaseItem> returnItems;
int totalCount = 0;
if (query.EnableTotalRecordCount)
{
- var itemsArray = itemsList.ToArray();
- totalCount = itemsArray.Length;
- returnItems = itemsArray;
+ var itemArray = itemsList.ToArray();
+ totalCount = itemArray.Length;
+ returnItems = itemArray;
}
else
{
- returnItems = itemsList.ToArray();
+ returnItems = itemsList;
}
if (limit.HasValue)
{
- returnItems = returnItems.Skip(startIndex ?? 0).Take(limit.Value).ToArray();
+ returnItems = returnItems.Skip(startIndex ?? 0).Take(limit.Value);
}
else if (startIndex.HasValue)
{
- returnItems = returnItems.Skip(startIndex.Value).ToArray();
+ returnItems = returnItems.Skip(startIndex.Value);
}
return new QueryResult<BaseItem>
@@ -1427,7 +1428,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.Item2 != null);
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren;
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
@@ -1594,7 +1595,7 @@ namespace MediaBrowser.Controller.Entities
return !IsPlayed(user);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public virtual bool SupportsUserDataFromChildren
{
get
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 44cb62d22..773c7df34 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -34,13 +34,13 @@ namespace MediaBrowser.Controller.Entities
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsDisplayedAsFolder => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
public override bool IsSaveLocalMetadataEnabled()
@@ -61,7 +61,7 @@ namespace MediaBrowser.Controller.Entities
return LibraryManager.GetItemList(query);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs
index 3bdb9b64a..dd8e3c45f 100644
--- a/MediaBrowser.Controller/Entities/IHasTrailers.cs
+++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@@ -11,29 +10,82 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the remote trailers.
/// </summary>
/// <value>The remote trailers.</value>
- MediaUrl[] RemoteTrailers { get; set; }
+ IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
/// <summary>
/// Gets or sets the local trailer ids.
/// </summary>
/// <value>The local trailer ids.</value>
- Guid[] LocalTrailerIds { get; set; }
- Guid[] RemoteTrailerIds { get; set; }
+ IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+
+ /// <summary>
+ /// Gets or sets the remote trailer ids.
+ /// </summary>
+ /// <value>The remote trailer ids.</value>
+ IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
+
Guid Id { get; set; }
}
+ /// <summary>
+ /// Class providing extension methods for working with <see cref="IHasTrailers" />.
+ /// </summary>
public static class HasTrailerExtensions
{
/// <summary>
+ /// Gets the trailer count.
+ /// </summary>
+ /// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
+ public static int GetTrailerCount(this IHasTrailers item)
+ => item.LocalTrailerIds.Count + item.RemoteTrailerIds.Count;
+
+ /// <summary>
/// Gets the trailer ids.
/// </summary>
- /// <returns>List&lt;Guid&gt;.</returns>
- public static List<Guid> GetTrailerIds(this IHasTrailers item)
+ /// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
+ public static IReadOnlyList<Guid> GetTrailerIds(this IHasTrailers item)
{
- var list = item.LocalTrailerIds.ToList();
- list.AddRange(item.RemoteTrailerIds);
- return list;
+ var localIds = item.LocalTrailerIds;
+ var remoteIds = item.RemoteTrailerIds;
+
+ var all = new Guid[localIds.Count + remoteIds.Count];
+ var index = 0;
+ foreach (var id in localIds)
+ {
+ all[index++] = id;
+ }
+
+ foreach (var id in remoteIds)
+ {
+ all[index++] = id;
+ }
+
+ return all;
}
+ /// <summary>
+ /// Gets the trailers.
+ /// </summary>
+ /// <returns><see cref="IReadOnlyList{BaseItem}" />.</returns>
+ public static IReadOnlyList<BaseItem> GetTrailers(this IHasTrailers item)
+ {
+ var localIds = item.LocalTrailerIds;
+ var remoteIds = item.RemoteTrailerIds;
+ var libraryManager = BaseItem.LibraryManager;
+
+ var all = new BaseItem[localIds.Count + remoteIds.Count];
+ var index = 0;
+ foreach (var id in localIds)
+ {
+ all[index++] = libraryManager.GetItemById(id);
+ }
+
+ foreach (var id in remoteIds)
+ {
+ all[index++] = libraryManager.GetItemById(id);
+ }
+
+ return all;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
index 848493864..fc46dec2e 100644
--- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs
+++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
@@ -1,6 +1,6 @@
using System;
+using System.Text.Json.Serialization;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Entities
public int Height { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsLocalFile => Path == null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase);
}
}
diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs
index bb2d03246..d88c31007 100644
--- a/MediaBrowser.Controller/Entities/LinkedChild.cs
+++ b/MediaBrowser.Controller/Entities/LinkedChild.cs
@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.Text.Json.Serialization;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
public LinkedChildType Type { get; set; }
public string LibraryItemId { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string Id { get; set; }
/// <summary>
@@ -29,7 +30,7 @@ namespace MediaBrowser.Controller.Entities
if (string.IsNullOrEmpty(child.Path))
{
- child.LibraryItemId = item.Id.ToString("N");
+ child.LibraryItemId = item.Id.ToString("N", CultureInfo.InvariantCulture);
}
return child;
@@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.Entities
public LinkedChild()
{
- Id = Guid.NewGuid().ToString("N");
+ Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index a532b5ee9..feaf8c45a 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.Movies
@@ -24,17 +24,20 @@ namespace MediaBrowser.Controller.Entities.Movies
DisplayOrder = ItemSortBy.PremiereDate;
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool FilterLinkedChildrenPerUser => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => true;
- public Guid[] LocalTrailerIds { get; set; }
- public Guid[] RemoteTrailerIds { get; set; }
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// Gets or sets the display order.
@@ -61,7 +64,8 @@ namespace MediaBrowser.Controller.Entities.Movies
{
return base.GetNonCachedChildren(directoryService);
}
- return new List<BaseItem>();
+
+ return Enumerable.Empty<BaseItem>();
}
protected override List<BaseItem> LoadChildren()
@@ -75,7 +79,7 @@ namespace MediaBrowser.Controller.Entities.Movies
return new List<BaseItem>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
private bool IsLegacyBoxSet
{
get
@@ -94,7 +98,7 @@ namespace MediaBrowser.Controller.Entities.Movies
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPreSorted => true;
public override bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 20c5b3521..11dc472b6 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Providers;
@@ -8,7 +9,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities.Movies
{
@@ -27,8 +27,11 @@ namespace MediaBrowser.Controller.Entities.Movies
RemoteTrailerIds = Array.Empty<Guid>();
}
- public Guid[] LocalTrailerIds { get; set; }
- public Guid[] RemoteTrailerIds { get; set; }
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// Gets or sets the name of the TMDB collection.
@@ -36,7 +39,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <value>The name of the TMDB collection.</value>
public string TmdbCollectionName { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string CollectionName
{
get => TmdbCollectionName;
@@ -183,7 +186,7 @@ namespace MediaBrowser.Controller.Entities.Movies
return list;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index 5bf082b7e..603242063 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -1,24 +1,23 @@
using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
{
- [IgnoreDataMember]
- public string[] Artists { get; set; }
+ /// <inheritdoc />
+ [JsonIgnore]
+ public IReadOnlyList<string> Artists { get; set; }
public MusicVideo()
{
Artists = Array.Empty<string>();
}
- [IgnoreDataMember]
- public string[] AllArtists => Artists;
-
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index dd0183489..d9b4b2206 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Entities
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
public override bool CanDelete()
@@ -63,13 +63,13 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool EnableAlphaNumericSorting => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
public static string GetPath(string name)
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 60c832189..86d62add9 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -1,21 +1,21 @@
+using System.Text.Json.Serialization;
using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class Photo : BaseItem
{
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsLocalMetadata => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Photo;
- [IgnoreDataMember]
+ [JsonIgnore]
public override Folder LatestItemsIndexContainer => AlbumEntity;
- [IgnoreDataMember]
+ [JsonIgnore]
public PhotoAlbum AlbumEntity
{
get
diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
index 4cd0c8b66..b86f1ac2a 100644
--- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs
+++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs
@@ -1,16 +1,16 @@
-using MediaBrowser.Model.Serialization;
+using System.Text.Json.Serialization;
namespace MediaBrowser.Controller.Entities
{
public class PhotoAlbum : Folder
{
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool AlwaysScanInternalMetadataPath => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index d6da0d48c..068032317 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -28,13 +28,13 @@ namespace MediaBrowser.Controller.Entities
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsDisplayedAsFolder => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Entities
return LibraryManager.GetItemList(query);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index fb29c07b0..49229fa4b 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -2,11 +2,11 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.TV
@@ -23,8 +23,11 @@ namespace MediaBrowser.Controller.Entities.TV
RemoteTrailerIds = Array.Empty<Guid>();
}
- public Guid[] LocalTrailerIds { get; set; }
- public Guid[] RemoteTrailerIds { get; set; }
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// Gets the season in which it aired.
@@ -46,25 +49,25 @@ namespace MediaBrowser.Controller.Entities.TV
return series == null ? SeriesName : series.SortName;
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool SupportsOwnedItems => IsStacked || MediaSourceCount > 1;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public int? AiredSeasonNumber => AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? ParentIndexNumber;
- [IgnoreDataMember]
+ [JsonIgnore]
public override Folder LatestItemsIndexContainer => Series;
- [IgnoreDataMember]
+ [JsonIgnore]
public override Guid DisplayParentId => SeasonId;
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool EnableDefaultVideoUserDataKeys => false;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -101,7 +104,7 @@ namespace MediaBrowser.Controller.Entities.TV
/// This Episode's Series Instance
/// </summary>
/// <value>The series.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Series Series
{
get
@@ -115,7 +118,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public Season Season
{
get
@@ -129,16 +132,16 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsInSeasonFolder => FindParent<Season>() != null;
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesName { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeasonName { get; set; }
public string FindSeriesPresentationUniqueKey()
@@ -221,7 +224,7 @@ namespace MediaBrowser.Controller.Entities.TV
return false;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsRemoteImageDownloading
{
get
@@ -235,12 +238,12 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsMissingEpisode => LocationType == LocationType.Virtual;
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid SeasonId { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid SeriesId { get; set; }
public Guid FindSeriesId()
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index 5d7c260d1..9c8a469e2 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.TV
@@ -15,22 +15,22 @@ namespace MediaBrowser.Controller.Entities.TV
/// </summary>
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
{
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPreSorted => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsDateLastMediaAdded => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override Guid DisplayParentId => SeriesId;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -71,7 +71,7 @@ namespace MediaBrowser.Controller.Entities.TV
/// This Episode's Series Instance
/// </summary>
/// <value>The series.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Series Series
{
get
@@ -85,7 +85,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesPath
{
get
@@ -179,13 +179,13 @@ namespace MediaBrowser.Controller.Entities.TV
return UnratedItem.Series;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesPresentationUniqueKey { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string SeriesName { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public Guid SeriesId { get; set; }
public string FindSeriesPresentationUniqueKey()
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index eae834f6f..76cb9a651 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
@@ -9,7 +11,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities.TV
@@ -30,23 +31,26 @@ namespace MediaBrowser.Controller.Entities.TV
public DayOfWeek[] AirDays { get; set; }
public string AirTime { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPreSorted => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsDateLastMediaAdded => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => true;
- public Guid[] LocalTrailerIds { get; set; }
- public Guid[] RemoteTrailerIds { get; set; }
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// airdate, dvd or absolute
@@ -91,7 +95,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
var folders = LibraryManager.GetCollectionFolders(this)
- .Select(i => i.Id.ToString("N"))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
.ToArray();
if (folders.Length == 0)
@@ -500,7 +504,7 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 5bf22d7bc..0b8be90cd 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -93,7 +93,7 @@ namespace MediaBrowser.Controller.Entities
return list;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 9952ba418..c70ecccf1 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -1,11 +1,12 @@
using System;
+using System.Globalization;
using System.IO;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Controller.Entities
@@ -16,13 +17,6 @@ namespace MediaBrowser.Controller.Entities
public class User : BaseItem
{
public static IUserManager UserManager { get; set; }
- public static IXmlSerializer XmlSerializer { get; set; }
-
- /// <summary>
- /// From now on all user paths will be Id-based.
- /// This is for backwards compatibility.
- /// </summary>
- public bool UsesIdForConfigurationPath { get; set; }
/// <summary>
/// Gets or sets the password.
@@ -30,9 +24,8 @@ namespace MediaBrowser.Controller.Entities
/// <value>The password.</value>
public string Password { get; set; }
public string EasyPassword { get; set; }
- public string Salt { get; set; }
- // Strictly to remove IgnoreDataMember
+ // Strictly to remove JsonIgnore
public override ItemImageInfo[] ImageInfos
{
get => base.ImageInfos;
@@ -43,7 +36,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string Path
{
get => ConfigurationDirectoryPath;
@@ -72,14 +65,14 @@ namespace MediaBrowser.Controller.Entities
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
/// <summary>
/// Gets the root folder.
/// </summary>
/// <value>The root folder.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public Folder RootFolder => LibraryManager.GetUserRootFolder();
/// <summary>
@@ -95,7 +88,7 @@ namespace MediaBrowser.Controller.Entities
private volatile UserConfiguration _config;
private readonly object _configSyncLock = new object();
- [IgnoreDataMember]
+ [JsonIgnore]
public UserConfiguration Configuration
{
get
@@ -118,7 +111,7 @@ namespace MediaBrowser.Controller.Entities
private volatile UserPolicy _policy;
private readonly object _policySyncLock = new object();
- [IgnoreDataMember]
+ [JsonIgnore]
public UserPolicy Policy
{
get
@@ -147,46 +140,23 @@ namespace MediaBrowser.Controller.Entities
/// <exception cref="ArgumentNullException"></exception>
public Task Rename(string newName)
{
- if (string.IsNullOrEmpty(newName))
- {
- throw new ArgumentNullException(nameof(newName));
- }
-
- // If only the casing is changing, leave the file system alone
- if (!UsesIdForConfigurationPath && !string.Equals(newName, Name, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(newName))
{
- UsesIdForConfigurationPath = true;
-
- // Move configuration
- var newConfigDirectory = GetConfigurationDirectoryPath(newName);
- var oldConfigurationDirectory = ConfigurationDirectoryPath;
-
- // Exceptions will be thrown if these paths already exist
- if (Directory.Exists(newConfigDirectory))
- {
- Directory.Delete(newConfigDirectory, true);
- }
-
- if (Directory.Exists(oldConfigurationDirectory))
- {
- Directory.Move(oldConfigurationDirectory, newConfigDirectory);
- }
- else
- {
- Directory.CreateDirectory(newConfigDirectory);
- }
+ throw new ArgumentException("Username can't be empty", nameof(newName));
}
Name = newName;
- return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
- {
- ReplaceAllMetadata = true,
- ImageRefreshMode = MetadataRefreshMode.FullRefresh,
- MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
- ForceSave = true
+ return RefreshMetadata(
+ new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
+ {
+ ReplaceAllMetadata = true,
+ ImageRefreshMode = MetadataRefreshMode.FullRefresh,
+ MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
+ ForceSave = true
- }, CancellationToken.None);
+ },
+ CancellationToken.None);
}
public override void UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
@@ -198,7 +168,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets the path to the user's configuration directory
/// </summary>
/// <value>The configuration directory path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string ConfigurationDirectoryPath => GetConfigurationDirectoryPath(Name);
public override double GetDefaultPrimaryImageAspectRatio()
@@ -215,22 +185,9 @@ namespace MediaBrowser.Controller.Entities
{
var parentPath = ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath;
- // Legacy
- if (!UsesIdForConfigurationPath)
- {
- if (string.IsNullOrEmpty(username))
- {
- throw new ArgumentNullException(nameof(username));
- }
-
- var safeFolderName = FileSystem.GetValidFilename(username);
-
- return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, safeFolderName);
- }
-
// TODO: Remove idPath and just use usernamePath for future releases
var usernamePath = System.IO.Path.Combine(parentPath, username);
- var idPath = System.IO.Path.Combine(parentPath, Id.ToString("N"));
+ var idPath = System.IO.Path.Combine(parentPath, Id.ToString("N", CultureInfo.InvariantCulture));
if (!Directory.Exists(usernamePath) && Directory.Exists(idPath))
{
Directory.Move(idPath, usernamePath);
@@ -295,7 +252,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public long InternalId { get; set; }
diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs
index f7136bdf2..ab425ee0f 100644
--- a/MediaBrowser.Controller/Entities/UserItemData.cs
+++ b/MediaBrowser.Controller/Entities/UserItemData.cs
@@ -1,5 +1,5 @@
using System;
-using MediaBrowser.Model.Serialization;
+using System.Text.Json.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -93,7 +93,7 @@ namespace MediaBrowser.Controller.Entities
/// This should never be serialized.
/// </summary>
/// <value><c>null</c> if [likes] contains no value, <c>true</c> if [likes]; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool? Likes
{
get
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 7fe8df8af..7fcf48a48 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -33,10 +33,10 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
private void ClearCache()
@@ -75,10 +75,10 @@ namespace MediaBrowser.Controller.Entities
return GetChildren(user, true).Count;
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool SupportsShortcutChildren => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPreSorted => true;
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 4a6d32dce..fd045f0dd 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities
public static ITVSeriesManager TVSeriesManager;
- [IgnoreDataMember]
+ [JsonIgnore]
public string CollectionType => ViewType;
public override IEnumerable<Guid> GetIdsForAncestorQuery()
@@ -40,10 +40,10 @@ namespace MediaBrowser.Controller.Entities
return list;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => false;
public override int GetChildCount(User user)
@@ -167,7 +167,7 @@ namespace MediaBrowser.Controller.Entities
return Task.CompletedTask;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index e483c8f34..454bdc4ae 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Movies;
@@ -987,7 +988,7 @@ namespace MediaBrowser.Controller.Entities
private UserView GetUserViewWithName(string name, string type, string sortName, BaseItem parent)
{
- return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N"), type, sortName);
+ return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N", CultureInfo.InvariantCulture), type, sortName);
}
private UserView GetUserView(string type, string localizationKey, string sortName, BaseItem parent)
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 8379dcc09..60906bdb0 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
@@ -13,7 +14,6 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
{
@@ -25,23 +25,23 @@ namespace MediaBrowser.Controller.Entities
ISupportsPlaceHolders,
IHasMediaSources
{
- [IgnoreDataMember]
+ [JsonIgnore]
public string PrimaryVersionId { get; set; }
public string[] AdditionalParts { get; set; }
public string[] LocalAlternateVersions { get; set; }
public LinkedChild[] LinkedAlternateVersions { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPositionTicksResume
{
get
@@ -90,7 +90,7 @@ namespace MediaBrowser.Controller.Entities
return base.CreatePresentationUniqueKey();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsThemeMedia => true;
/// <summary>
@@ -180,10 +180,10 @@ namespace MediaBrowser.Controller.Entities
return IsFileProtocol;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public int MediaSourceCount
{
get
@@ -200,10 +200,10 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsStacked => AdditionalParts.Length > 0;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool HasLocalAlternateVersions => LocalAlternateVersions.Length > 0;
public IEnumerable<Guid> GetAdditionalPartIds()
@@ -218,7 +218,7 @@ namespace MediaBrowser.Controller.Entities
public static ILiveTvManager LiveTvManager { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public override SourceType SourceType
{
get
@@ -247,7 +247,7 @@ namespace MediaBrowser.Controller.Entities
return base.CanDelete();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsCompleteMedia
{
get
@@ -261,7 +261,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected virtual bool EnableDefaultVideoUserDataKeys => true;
public override List<string> GetUserDataKeys()
@@ -338,7 +338,7 @@ namespace MediaBrowser.Controller.Entities
.OrderBy(i => i.SortName);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath
{
get
@@ -360,7 +360,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override string FileNameWithoutExtension
{
get
@@ -432,14 +432,14 @@ namespace MediaBrowser.Controller.Entities
/// Gets a value indicating whether [is3 D].
/// </summary>
/// <value><c>true</c> if [is3 D]; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool Is3D => Video3DFormat.HasValue;
/// <summary>
/// Gets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Video;
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 13e82fada..a01ef5c31 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using MediaBrowser.Model.Serialization;
+using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Entities
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.Entities
return value;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
public override bool CanDelete()
@@ -72,7 +72,7 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 3f8cc0b83..61b2c15ae 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -83,7 +83,7 @@ namespace MediaBrowser.Controller
void EnableLoopback(string appName);
- WakeOnLanInfo[] GetWakeOnLanInfo();
+ IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
string ExpandVirtualPath(string path);
string ReverseVirtualPath(string path);
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 7f7370893..bbedc0442 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -23,6 +23,12 @@ namespace MediaBrowser.Controller.Library
IEnumerable<User> Users { get; }
/// <summary>
+ /// Gets the user ids.
+ /// </summary>
+ /// <value>The users ids.</value>
+ IEnumerable<Guid> UsersIds { get; }
+
+ /// <summary>
/// Occurs when [user updated].
/// </summary>
event EventHandler<GenericEventArgs<User>> UserUpdated;
@@ -92,7 +98,7 @@ namespace MediaBrowser.Controller.Library
/// <returns>User.</returns>
/// <exception cref="ArgumentNullException">name</exception>
/// <exception cref="ArgumentException"></exception>
- Task<User> CreateUser(string name);
+ User CreateUser(string name);
/// <summary>
/// Deletes the user.
@@ -101,7 +107,7 @@ namespace MediaBrowser.Controller.Library
/// <returns>Task.</returns>
/// <exception cref="ArgumentNullException">user</exception>
/// <exception cref="ArgumentException"></exception>
- Task DeleteUser(User user);
+ void DeleteUser(User user);
/// <summary>
/// Resets the password.
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
index c719ad81c..2ea0a748e 100644
--- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -10,10 +10,15 @@ namespace MediaBrowser.Controller.LiveTv
public interface IListingsProvider
{
string Name { get; }
+
string Type { get; }
+
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
+
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
+
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
+
Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index f99df6c7c..e02c387e4 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="fields">The fields.</param>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
- Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> programs, ItemFields[] fields, User user = null);
+ Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, ItemFields[] fields, User user = null);
/// <summary>
/// Saves the tuner host.
@@ -258,7 +258,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="items">The items.</param>
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
- void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
+ void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user);
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 55f47aae9..60391bb83 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -2,13 +2,13 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@@ -31,13 +31,13 @@ namespace MediaBrowser.Controller.LiveTv
return UnratedItem.LiveTvChannel;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPositionTicksResume => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override SourceType SourceType => SourceType.LiveTV;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool EnableRememberingTrackSelections => false;
/// <summary>
@@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The type of the channel.</value>
public ChannelType ChannelType { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public override LocationType LocationType => LocationType.Remote;
protected override string CreateSortName()
@@ -70,7 +70,7 @@ namespace MediaBrowser.Controller.LiveTv
return (Number ?? string.Empty) + "-" + (Name ?? string.Empty);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
public override string GetClientTypeName()
@@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.LiveTv
var info = new MediaSourceInfo
{
- Id = Id.ToString("N"),
+ Id = Id.ToString("N", CultureInfo.InvariantCulture),
Protocol = PathProtocol ?? MediaProtocol.File,
MediaStreams = new List<MediaStream>(),
Name = Name,
@@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.LiveTv
protected override string GetInternalMetadataPath(string basePath)
{
- return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N", CultureInfo.InvariantCulture), "metadata");
}
public override bool CanDelete()
@@ -119,45 +119,45 @@ namespace MediaBrowser.Controller.LiveTv
return false;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsMovie { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsSports { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
/// </summary>
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsSeries { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsNews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsRepeat { get; set; }
/// <summary>
/// Gets or sets the episode title.
/// </summary>
/// <value>The episode title.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string EpisodeTitle { get; set; }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 8bde6a5da..13df85aed 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -8,7 +10,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Providers;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@@ -62,79 +63,79 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override SourceType SourceType => SourceType.LiveTV;
/// <summary>
/// The start date of the program, in UTC.
/// </summary>
- [IgnoreDataMember]
+ [JsonIgnore]
public DateTime StartDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is repeat.
/// </summary>
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsRepeat { get; set; }
/// <summary>
/// Gets or sets the episode title.
/// </summary>
/// <value>The episode title.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public string EpisodeTitle { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public string ShowId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is movie.
/// </summary>
/// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsMovie { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsSports => Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
/// </summary>
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsSeries { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or sets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or sets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or sets a value indicating whether this instance is premiere.
/// </summary>
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
/// <summary>
@@ -142,10 +143,10 @@ namespace MediaBrowser.Controller.LiveTv
/// If the item is a folder, it returns the folder itself
/// </summary>
/// <value>The containing folder path.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath => Path;
- //[IgnoreDataMember]
+ //[JsonIgnore]
//public override string MediaType
//{
// get
@@ -154,7 +155,7 @@ namespace MediaBrowser.Controller.LiveTv
// }
//}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsAiring
{
get
@@ -165,7 +166,7 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool HasAired
{
get
@@ -188,7 +189,7 @@ namespace MediaBrowser.Controller.LiveTv
protected override string GetInternalMetadataPath(string basePath)
{
- return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N", CultureInfo.InvariantCulture));
}
public override bool CanDelete()
@@ -196,7 +197,7 @@ namespace MediaBrowser.Controller.LiveTv
return false;
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPeople
{
get
@@ -211,7 +212,7 @@ namespace MediaBrowser.Controller.LiveTv
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsAncestors => false;
private LiveTvOptions GetConfiguration()
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
index 2fea6a8cb..46774b2b7 100644
--- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@@ -129,10 +129,10 @@ namespace MediaBrowser.Controller.LiveTv
/// Gets or sets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
public int? ProductionYear { get; set; }
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 01893f1b5..c6bca2518 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -19,6 +19,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
</Project>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index b9ccc93ef..d896a7aef 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
@@ -22,8 +23,17 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly IMediaEncoder _mediaEncoder;
private readonly IFileSystem _fileSystem;
private readonly ISubtitleEncoder _subtitleEncoder;
- // private readonly IApplicationPaths _appPaths;
- // private readonly IAssemblyInfo _assemblyInfo;
+
+ private static readonly string[] _videoProfiles = new[]
+ {
+ "ConstrainedBaseline",
+ "Baseline",
+ "Extended",
+ "Main",
+ "High",
+ "ProgressiveHigh",
+ "ConstrainedHigh"
+ };
public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder)
{
@@ -33,9 +43,13 @@ namespace MediaBrowser.Controller.MediaEncoding
}
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
- {
- var defaultEncoder = "libx264";
+ => GetH264OrH265Encoder("libx264", "h264", state, encodingOptions);
+
+ public string GetH265Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
+ => GetH264OrH265Encoder("libx265", "hevc", state, encodingOptions);
+ private string GetH264OrH265Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions)
+ {
// Only use alternative encoders for video files.
// When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
@@ -45,35 +59,30 @@ namespace MediaBrowser.Controller.MediaEncoding
var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
- {"qsv", "h264_qsv"},
- {"h264_qsv", "h264_qsv"},
- {"nvenc", "h264_nvenc"},
- {"amf", "h264_amf"},
- {"omx", "h264_omx"},
- {"h264_v4l2m2m", "h264_v4l2m2m"},
- {"mediacodec", "h264_mediacodec"},
- {"vaapi", "h264_vaapi"}
+ {"qsv", hwEncoder + "_qsv"},
+ {hwEncoder + "_qsv", hwEncoder + "_qsv"},
+ {"nvenc", hwEncoder + "_nvenc"},
+ {"amf", hwEncoder + "_amf"},
+ {"omx", hwEncoder + "_omx"},
+ {hwEncoder + "_v4l2m2m", hwEncoder + "_v4l2m2m"},
+ {"mediacodec", hwEncoder + "_mediacodec"},
+ {"vaapi", hwEncoder + "_vaapi"}
};
if (!string.IsNullOrEmpty(hwType)
- && encodingOptions.EnableHardwareEncoding && codecMap.ContainsKey(hwType))
+ && encodingOptions.EnableHardwareEncoding
+ && codecMap.ContainsKey(hwType)
+ && CheckVaapi(state, hwType, encodingOptions))
{
- if (CheckVaapi(state, hwType, encodingOptions))
- {
- var preferredEncoder = codecMap[hwType];
+ var preferredEncoder = codecMap[hwType];
- if (_mediaEncoder.SupportsEncoder(preferredEncoder))
- {
- return preferredEncoder;
- }
+ if (_mediaEncoder.SupportsEncoder(preferredEncoder))
+ {
+ return preferredEncoder;
}
}
-
}
- // Avoid performing a second attempt when the first one
- // hasn't tried hardware encoding anyway.
- encodingOptions.EnableHardwareEncoding = false;
return defaultEncoder;
}
@@ -98,15 +107,13 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var videoStream = state.VideoStream;
- if (videoStream != null)
+ // vaapi will throw an error with this input
+ // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
+ if (string.Equals(videoStream?.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase))
{
- // vaapi will throw an error with this input
- // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
- if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
+ return false;
}
+
return true;
}
@@ -119,18 +126,27 @@ namespace MediaBrowser.Controller.MediaEncoding
if (!string.IsNullOrEmpty(codec))
{
+ if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
+ {
+ return GetH265Encoder(state, encodingOptions);
+ }
+
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
{
return GetH264Encoder(state, encodingOptions);
}
+
if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
{
return "libvpx";
}
+
if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
{
return "wmv2";
}
+
if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
{
return "libtheora";
@@ -149,11 +165,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns>System.String.</returns>
public string GetUserAgentParam(EncodingJobInfo state)
{
- string useragent = null;
-
- state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent);
-
- if (!string.IsNullOrEmpty(useragent))
+ if (state.RemoteHttpHeaders.TryGetValue("User-Agent", out string useragent))
{
return "-user_agent \"" + useragent + "\"";
}
@@ -180,50 +192,62 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return null;
}
+
if (string.Equals(container, "wmv", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "mts", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "vob", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "mpg", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "rec", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "dvr-ms", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "ogm", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "divx", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "tp", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "rmvb", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(container, "rtp", StringComparison.OrdinalIgnoreCase))
{
return null;
@@ -251,10 +275,12 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return null;
}
+
if (string.Equals(codec, "aac_latm", StringComparison.OrdinalIgnoreCase))
{
return null;
}
+
if (string.Equals(codec, "eac3", StringComparison.OrdinalIgnoreCase))
{
return null;
@@ -279,30 +305,37 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return "mp3";
}
+
if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
{
return "aac";
}
+
if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
{
return "wma";
}
+
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
+
if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
+
if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
+
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
}
+
if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
{
return "vorbis";
@@ -324,14 +357,17 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return "wmv";
}
+
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return "vpx";
}
+
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return "theora";
}
+
if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
{
return "h264";
@@ -342,19 +378,9 @@ namespace MediaBrowser.Controller.MediaEncoding
public int GetVideoProfileScore(string profile)
{
- var list = new[]
- {
- "ConstrainedBaseline",
- "Baseline",
- "Extended",
- "Main",
- "High",
- "ProgressiveHigh",
- "ConstrainedHigh"
- };
-
// strip spaces because they may be stripped out on the query string
- return Array.FindIndex(list, t => string.Equals(t, profile.Replace(" ", ""), StringComparison.OrdinalIgnoreCase));
+ profile = profile.Replace(" ", "");
+ return Array.FindIndex(_videoProfiles, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase));
}
public string GetInputPathArgument(EncodingJobInfo state)
@@ -362,14 +388,19 @@ namespace MediaBrowser.Controller.MediaEncoding
var protocol = state.InputProtocol;
var mediaPath = state.MediaPath ?? string.Empty;
- var inputPath = new[] { mediaPath };
-
- if (state.IsInputVideo)
+ string[] inputPath;
+ if (state.IsInputVideo
+ && !(state.VideoType == VideoType.Iso && state.IsoMount == null))
{
- if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
- {
- inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
- }
+ inputPath = MediaEncoderHelpers.GetInputArgument(
+ _fileSystem,
+ mediaPath,
+ state.IsoMount,
+ state.PlayableStreamFileNames);
+ }
+ else
+ {
+ inputPath = new[] { mediaPath };
}
return _mediaEncoder.GetInputArgument(inputPath, protocol);
@@ -388,18 +419,22 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return "aac -strict experimental";
}
+
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
{
return "libmp3lame";
}
+
if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
{
return "libvorbis";
}
+
if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
{
return "wmav2";
}
+
if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase))
{
return "libopus";
@@ -413,54 +448,59 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions)
{
- var request = state.BaseRequest;
+ var arg = new StringBuilder();
- var arg = string.Format("-i {0}", GetInputPathArgument(state));
-
- if (state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
+ if (state.IsVideoRequest
+ && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
{
- if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+ var hwOutputFormat = "vaapi";
+
+ if (hasGraphicalSubs)
{
- if (state.VideoStream != null && state.VideoStream.Width.HasValue)
- {
- // This is hacky but not sure how to get the exact subtitle resolution
- int height = Convert.ToInt32((double)state.VideoStream.Width.Value / 16.0 * 9.0);
+ hwOutputFormat = "yuv420p";
+ }
- arg += string.Format(" -canvas_size {0}:{1}", state.VideoStream.Width.Value.ToString(CultureInfo.InvariantCulture), height.ToString(CultureInfo.InvariantCulture));
- }
+ arg.Append("-hwaccel vaapi -hwaccel_output_format ")
+ .Append(hwOutputFormat)
+ .Append(" -vaapi_device ")
+ .Append(encodingOptions.VaapiDevice)
+ .Append(' ');
+ }
- var subtitlePath = state.SubtitleStream.Path;
+ arg.Append("-i ")
+ .Append(GetInputPathArgument(state));
- if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase))
- {
- var idxFile = Path.ChangeExtension(subtitlePath, ".idx");
- if (File.Exists(idxFile))
- {
- subtitlePath = idxFile;
- }
- }
+ if (state.SubtitleStream != null
+ && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
+ && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
+ {
+ if (state.VideoStream != null && state.VideoStream.Width.HasValue)
+ {
+ // This is hacky but not sure how to get the exact subtitle resolution
+ int height = Convert.ToInt32(state.VideoStream.Width.Value / 16.0 * 9.0);
- arg += " -i \"" + subtitlePath + "\"";
+ arg.Append(" -canvas_size ")
+ .Append(state.VideoStream.Width.Value.ToString(CultureInfo.InvariantCulture))
+ .Append(':')
+ .Append(height.ToString(CultureInfo.InvariantCulture));
}
- }
- if (state.IsVideoRequest)
- {
- if (GetVideoEncoder(state, encodingOptions).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
- {
- var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
- var hwOutputFormat = "vaapi";
+ var subtitlePath = state.SubtitleStream.Path;
- if (hasGraphicalSubs)
+ if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase))
+ {
+ var idxFile = Path.ChangeExtension(subtitlePath, ".idx");
+ if (File.Exists(idxFile))
{
- hwOutputFormat = "yuv420p";
+ subtitlePath = idxFile;
}
-
- arg = "-hwaccel vaapi -hwaccel_output_format " + hwOutputFormat + " -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
}
+
+ arg.Append(" -i \"").Append(subtitlePath).Append('\"');
}
- return arg.Trim();
+ return arg.ToString();
}
/// <summary>
@@ -472,8 +512,32 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var codec = stream.Codec ?? string.Empty;
- return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 ||
- codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
+ return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1
+ || codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1;
+ }
+
+ public bool IsH265(MediaStream stream)
+ {
+ var codec = stream.Codec ?? string.Empty;
+
+ return codec.IndexOf("265", StringComparison.OrdinalIgnoreCase) != -1
+ || codec.IndexOf("hevc", StringComparison.OrdinalIgnoreCase) != -1;
+ }
+
+ public string GetBitStreamArgs(MediaStream stream)
+ {
+ if (IsH264(stream))
+ {
+ return "-bsf:v h264_mp4toannexb";
+ }
+ else if (IsH265(stream))
+ {
+ return "-bsf:v hevc_mp4toannexb";
+ }
+ else
+ {
+ return null;
+ }
}
public string GetVideoBitrateParam(EncodingJobInfo state, string videoCodec)
@@ -486,26 +550,38 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// With vpx when crf is used, b:v becomes a max rate
// https://trac.ffmpeg.org/wiki/vpxEncodingGuide.
- return string.Format(" -maxrate:v {0} -bufsize:v {1} -b:v {0}", bitrate.Value.ToString(_usCulture), (bitrate.Value * 2).ToString(_usCulture));
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ " -maxrate:v {0} -bufsize:v {1} -b:v {0}",
+ bitrate.Value,
+ bitrate.Value * 2);
}
if (string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
- return string.Format(" -b:v {0}", bitrate.Value.ToString(_usCulture));
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ " -b:v {0}",
+ bitrate.Value);
}
- if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase))
{
// h264
- return string.Format(" -maxrate {0} -bufsize {1}",
- bitrate.Value.ToString(_usCulture),
- (bitrate.Value * 2).ToString(_usCulture));
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ " -maxrate {0} -bufsize {1}",
+ bitrate.Value,
+ bitrate.Value * 2);
}
// h264
- return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}",
- bitrate.Value.ToString(_usCulture),
- (bitrate.Value * 2).ToString(_usCulture));
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ " -b:v {0} -maxrate {0} -bufsize {1}",
+ bitrate.Value,
+ bitrate.Value * 2);
}
return string.Empty;
@@ -515,8 +591,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{
// Clients may direct play higher than level 41, but there's no reason to transcode higher
if (double.TryParse(level, NumberStyles.Any, _usCulture, out double requestLevel)
- && string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)
- && requestLevel > 41)
+ && requestLevel > 41
+ && (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoCodec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoCodec, "hevc", StringComparison.OrdinalIgnoreCase)))
{
return "41";
}
@@ -536,7 +614,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// hls always copies timestamps
var setPtsParam = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive
? string.Empty
- : string.Format(",setpts=PTS -{0}/TB", seconds.ToString(_usCulture));
+ : string.Format(CultureInfo.InvariantCulture, ",setpts=PTS -{0}/TB", seconds);
// TODO
// var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf");
@@ -620,49 +698,53 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// Gets the video bitrate to specify on the command line
/// </summary>
- public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultH264Preset)
+ public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultPreset)
{
var param = string.Empty;
var isVc1 = state.VideoStream != null &&
string.Equals(state.VideoStream.Codec, "vc1", StringComparison.OrdinalIgnoreCase);
+ var isLibX265 = string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase);
- if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) || isLibX265)
{
- if (!string.IsNullOrEmpty(encodingOptions.H264Preset))
+ if (!string.IsNullOrEmpty(encodingOptions.EncoderPreset))
{
- param += "-preset " + encodingOptions.H264Preset;
+ param += "-preset " + encodingOptions.EncoderPreset;
}
else
{
- param += "-preset " + defaultH264Preset;
+ param += "-preset " + defaultPreset;
}
- if (encodingOptions.H264Crf >= 0 && encodingOptions.H264Crf <= 51)
+ int encodeCrf = encodingOptions.H264Crf;
+ if (isLibX265)
{
- param += " -crf " + encodingOptions.H264Crf.ToString(CultureInfo.InvariantCulture);
+ encodeCrf = encodingOptions.H265Crf;
}
- else
+
+ if (encodeCrf >= 0 && encodeCrf <= 51)
{
- param += " -crf 23";
+ param += " -crf " + encodeCrf.ToString(CultureInfo.InvariantCulture);
}
- }
-
- else if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
- {
- param += "-preset fast";
+ else
+ {
+ string defaultCrf = "23";
+ if (isLibX265)
+ {
+ defaultCrf = "28";
+ }
- param += " -crf 28";
+ param += " -crf " + defaultCrf;
+ }
}
-
- // h264 (h264_qsv)
- else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) // h264 (h264_qsv)
{
string[] valid_h264_qsv = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" };
- if (valid_h264_qsv.Contains(encodingOptions.H264Preset, StringComparer.OrdinalIgnoreCase))
+ if (valid_h264_qsv.Contains(encodingOptions.EncoderPreset, StringComparer.OrdinalIgnoreCase))
{
- param += "-preset " + encodingOptions.H264Preset;
+ param += "-preset " + encodingOptions.EncoderPreset;
}
else
{
@@ -672,11 +754,10 @@ namespace MediaBrowser.Controller.MediaEncoding
param += " -look_ahead 0";
}
-
- // h264 (h264_nvenc)
- else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
+ || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase))
{
- switch (encodingOptions.H264Preset)
+ switch (encodingOptions.EncoderPreset)
{
case "veryslow":
@@ -705,9 +786,7 @@ namespace MediaBrowser.Controller.MediaEncoding
break;
}
}
-
- // webm
- else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm
{
// Values 0-3, 0 being highest quality but slower
var profileScore = 0;
@@ -733,18 +812,14 @@ namespace MediaBrowser.Controller.MediaEncoding
qmin,
qmax);
}
-
else if (string.Equals(videoEncoder, "mpeg4", StringComparison.OrdinalIgnoreCase))
{
param += "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
}
-
- // asf/wmv
- else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "wmv2", StringComparison.OrdinalIgnoreCase)) // asf/wmv
{
param += "-qmin 2";
}
-
else if (string.Equals(videoEncoder, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
param += "-mbd 2";
@@ -760,21 +835,21 @@ namespace MediaBrowser.Controller.MediaEncoding
var targetVideoCodec = state.ActualOutputVideoCodec;
- var request = state.BaseRequest;
var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault();
// vaapi does not support Baseline profile, force Constrained Baseline in this case,
// which is compatible (and ugly)
- if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
- profile != null && profile.ToLowerInvariant().Contains("baseline"))
+ if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
+ && profile != null
+ && profile.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) != -1)
{
- profile = "constrained_baseline";
+ profile = "constrained_baseline";
}
if (!string.IsNullOrEmpty(profile))
{
- if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + profile;
@@ -789,8 +864,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// h264_qsv and h264_nvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format
// also needed for libx264 due to https://trac.ffmpeg.org/ticket/3307
- if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
{
switch (level)
{
@@ -826,10 +902,11 @@ namespace MediaBrowser.Controller.MediaEncoding
break;
}
}
- // nvenc doesn't decode with param -level set ?!
- else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase))
{
- //param += "";
+ // nvenc doesn't decode with param -level set ?!
+ // TODO:
}
else if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase))
{
@@ -842,10 +919,15 @@ namespace MediaBrowser.Controller.MediaEncoding
param += " -x264opts:0 subme=0:me_range=4:rc_lookahead=10:me=dia:no_chroma_me:8x8dct=0:partitions=none";
}
- if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase))
+ {
+ // todo
+ }
+
+ if (!string.Equals(videoEncoder, "h264_omx", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@@ -867,12 +949,10 @@ namespace MediaBrowser.Controller.MediaEncoding
return false;
}
- if (videoStream.IsInterlaced)
+ if (videoStream.IsInterlaced
+ && state.DeInterlace(videoStream.Codec, false))
{
- if (state.DeInterlace(videoStream.Codec, false))
- {
- return false;
- }
+ return false;
}
if (videoStream.IsAnamorphic ?? false)
@@ -884,24 +964,23 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Can't stream copy if we're burning in subtitles
- if (request.SubtitleStreamIndex.HasValue)
+ if (request.SubtitleStreamIndex.HasValue
+ && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
{
- if (state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
- {
- return false;
- }
+ return false;
}
- if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals("h264", videoStream.Codec, StringComparison.OrdinalIgnoreCase)
+ && videoStream.IsAVC.HasValue
+ && !videoStream.IsAVC.Value
+ && request.RequireAvc)
{
- if (videoStream.IsAVC.HasValue && !videoStream.IsAVC.Value && request.RequireAvc)
- {
- return false;
- }
+ return false;
}
// Source and target codecs must match
- if (string.IsNullOrEmpty(videoStream.Codec) || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
+ if (string.IsNullOrEmpty(videoStream.Codec)
+ || !state.SupportedVideoCodecs.Contains(videoStream.Codec, StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -931,21 +1010,17 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Video width must fall within requested value
- if (request.MaxWidth.HasValue)
+ if (request.MaxWidth.HasValue
+ && (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value))
{
- if (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value)
- {
- return false;
- }
+ return false;
}
// Video height must fall within requested value
- if (request.MaxHeight.HasValue)
+ if (request.MaxHeight.HasValue
+ && (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value))
{
- if (!videoStream.Height.HasValue || videoStream.Height.Value > request.MaxHeight.Value)
- {
- return false;
- }
+ return false;
}
// Video framerate must fall within requested value
@@ -961,12 +1036,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// Video bitrate must fall within requested value
- if (request.VideoBitRate.HasValue)
+ if (request.VideoBitRate.HasValue
+ && (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value))
{
- if (!videoStream.BitRate.HasValue || videoStream.BitRate.Value > request.VideoBitRate.Value)
- {
- return false;
- }
+ return false;
}
var maxBitDepth = state.GetRequestedVideoBitDepth(videoStream.Codec);
@@ -979,35 +1052,31 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var maxRefFrames = state.GetRequestedMaxRefFrames(videoStream.Codec);
- if (maxRefFrames.HasValue)
+ if (maxRefFrames.HasValue
+ && videoStream.RefFrames.HasValue && videoStream.RefFrames.Value > maxRefFrames.Value)
{
- if (videoStream.RefFrames.HasValue && videoStream.RefFrames.Value > maxRefFrames.Value)
- {
- return false;
- }
+ return false;
}
// If a specific level was requested, the source must match or be less than
var level = state.GetRequestedLevel(videoStream.Codec);
- if (!string.IsNullOrEmpty(level))
+ if (!string.IsNullOrEmpty(level)
+ && double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel))
{
- if (double.TryParse(level, NumberStyles.Any, _usCulture, out var requestLevel))
+ if (!videoStream.Level.HasValue)
{
- if (!videoStream.Level.HasValue)
- {
- //return false;
- }
+ //return false;
+ }
- if (videoStream.Level.HasValue && videoStream.Level.Value > requestLevel)
- {
- return false;
- }
+ if (videoStream.Level.HasValue && videoStream.Level.Value > requestLevel)
+ {
+ return false;
}
}
- if (string.Equals(state.InputContainer, "avi", StringComparison.OrdinalIgnoreCase) &&
- string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) &&
- !(videoStream.IsAVC ?? false))
+ if (string.Equals(state.InputContainer, "avi", StringComparison.OrdinalIgnoreCase)
+ && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase)
+ && !(videoStream.IsAVC ?? false))
{
// see Coach S01E01 - Kelly and the Professor(0).avi
return false;
@@ -1016,7 +1085,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return request.EnableAutoStreamCopy;
}
- public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, string[] supportedAudioCodecs)
+ public bool CanStreamCopyAudio(EncodingJobInfo state, MediaStream audioStream, IEnumerable<string> supportedAudioCodecs)
{
var request = state.BaseRequest;
@@ -1026,16 +1095,16 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var maxBitDepth = state.GetRequestedAudioBitDepth(audioStream.Codec);
- if (maxBitDepth.HasValue)
+ if (maxBitDepth.HasValue
+ && audioStream.BitDepth.HasValue
+ && audioStream.BitDepth.Value > maxBitDepth.Value)
{
- if (audioStream.BitDepth.HasValue && audioStream.BitDepth.Value > maxBitDepth.Value)
- {
- return false;
- }
+ return false;
}
// Source and target codecs must match
- if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))
+ if (string.IsNullOrEmpty(audioStream.Codec)
+ || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -1048,6 +1117,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return false;
}
+
if (audioStream.Channels.Value > channels.Value)
{
return false;
@@ -1061,6 +1131,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return false;
}
+
if (audioStream.SampleRate.Value > request.AudioSampleRate.Value)
{
return false;
@@ -1074,6 +1145,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return false;
}
+
if (audioStream.BitRate.Value > request.AudioBitRate.Value)
{
return false;
@@ -1089,29 +1161,29 @@ namespace MediaBrowser.Controller.MediaEncoding
if (videoStream != null)
{
- var isUpscaling = request.Height.HasValue && videoStream.Height.HasValue &&
- request.Height.Value > videoStream.Height.Value && request.Width.HasValue && videoStream.Width.HasValue &&
- request.Width.Value > videoStream.Width.Value;
+ var isUpscaling = request.Height.HasValue
+ && videoStream.Height.HasValue
+ && request.Height.Value > videoStream.Height.Value
+ && request.Width.HasValue
+ && videoStream.Width.HasValue
+ && request.Width.Value > videoStream.Width.Value;
// Don't allow bitrate increases unless upscaling
- if (!isUpscaling)
+ if (!isUpscaling && bitrate.HasValue && videoStream.BitRate.HasValue)
{
- if (bitrate.HasValue && videoStream.BitRate.HasValue)
- {
- bitrate = GetMinBitrate(videoStream.BitRate.Value, bitrate.Value);
- }
+ bitrate = GetMinBitrate(videoStream.BitRate.Value, bitrate.Value);
}
- }
-
- if (bitrate.HasValue)
- {
- var inputVideoCodec = videoStream.Codec;
- bitrate = ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
- // If a max bitrate was requested, don't let the scaled bitrate exceed it
- if (request.VideoBitRate.HasValue)
+ if (bitrate.HasValue)
{
- bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ var inputVideoCodec = videoStream.Codec;
+ bitrate = ScaleBitrate(bitrate.Value, inputVideoCodec, outputVideoCodec);
+
+ // If a max bitrate was requested, don't let the scaled bitrate exceed it
+ if (request.VideoBitRate.HasValue)
+ {
+ bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
+ }
}
}
@@ -1127,7 +1199,7 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else if (sourceBitrate <= 3000000)
{
- sourceBitrate = Convert.ToInt32(sourceBitrate * 2);
+ sourceBitrate *= 2;
}
var bitrate = Math.Min(sourceBitrate, requestedBitrate);
@@ -1137,12 +1209,13 @@ namespace MediaBrowser.Controller.MediaEncoding
private static double GetVideoBitrateScaleFactor(string codec)
{
- if (StringHelper.EqualsIgnoreCase(codec, "h265") ||
- StringHelper.EqualsIgnoreCase(codec, "hevc") ||
- StringHelper.EqualsIgnoreCase(codec, "vp9"))
+ if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "vp9", StringComparison.OrdinalIgnoreCase))
{
return .5;
}
+
return 1;
}
@@ -1169,21 +1242,15 @@ namespace MediaBrowser.Controller.MediaEncoding
scaleFactor = Math.Max(scaleFactor, 2);
}
- var newBitrate = scaleFactor * bitrate;
-
- return Convert.ToInt32(newBitrate);
+ return Convert.ToInt32(scaleFactor * bitrate);
}
public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream)
{
if (request.AudioBitRate.HasValue)
{
- // Make sure we don't request a bitrate higher than the source
- var currentBitrate = audioStream == null ? request.AudioBitRate.Value : audioStream.BitRate ?? request.AudioBitRate.Value;
-
// Don't encode any higher than this
return Math.Min(384000, request.AudioBitRate.Value);
- //return Math.Min(currentBitrate, request.AudioBitRate.Value);
}
return null;
@@ -1196,12 +1263,14 @@ namespace MediaBrowser.Controller.MediaEncoding
var filters = new List<string>();
// Boost volume to 200% when downsampling from 6ch to 2ch
- if (channels.HasValue && channels.Value <= 2)
+ if (channels.HasValue
+ && channels.Value <= 2
+ && state.AudioStream != null
+ && state.AudioStream.Channels.HasValue
+ && state.AudioStream.Channels.Value > 5
+ && !encodingOptions.DownMixAudioBoost.Equals(1))
{
- if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5 && !encodingOptions.DownMixAudioBoost.Equals(1))
- {
- filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture));
- }
+ filters.Add("volume=" + encodingOptions.DownMixAudioBoost.ToString(_usCulture));
}
var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive;
@@ -1209,12 +1278,16 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds;
- filters.Add(string.Format("asetpts=PTS-{0}/TB", Math.Round(seconds).ToString(_usCulture)));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "asetpts=PTS-{0}/TB",
+ Math.Round(seconds)));
}
if (filters.Count > 0)
{
- return "-af \"" + string.Join(",", filters.ToArray()) + "\"";
+ return "-af \"" + string.Join(",", filters) + "\"";
}
return string.Empty;
@@ -1231,18 +1304,17 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var request = state.BaseRequest;
- var inputChannels = audioStream == null
- ? null
- : audioStream.Channels;
+ var inputChannels = audioStream?.Channels;
if (inputChannels <= 0)
{
inputChannels = null;
}
- int? transcoderChannelLimit = null;
var codec = outputAudioCodec ?? string.Empty;
+
+ int? transcoderChannelLimit;
if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
{
// wmav2 currently only supports two channel output
@@ -1291,6 +1363,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
return val2;
}
+
if (!val2.HasValue)
{
return val1;
@@ -1364,7 +1437,10 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.VideoStream != null)
{
- args += string.Format("-map 0:{0}", state.VideoStream.Index);
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ "-map 0:{0}",
+ state.VideoStream.Index);
}
else
{
@@ -1374,7 +1450,10 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.AudioStream != null)
{
- args += string.Format(" -map 0:{0}", state.AudioStream.Index);
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ " -map 0:{0}",
+ state.AudioStream.Index);
}
else
@@ -1389,7 +1468,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else if (subtitleMethod == SubtitleDeliveryMethod.Embed)
{
- args += string.Format(" -map 0:{0}", state.SubtitleStream.Index);
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ " -map 0:{0}",
+ state.SubtitleStream.Index);
}
else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
{
@@ -1441,7 +1523,10 @@ namespace MediaBrowser.Controller.MediaEncoding
var request = state.BaseRequest;
// Add resolution params, if specified
- if (request.Width.HasValue || request.Height.HasValue || request.MaxHeight.HasValue || request.MaxWidth.HasValue)
+ if (request.Width.HasValue
+ || request.Height.HasValue
+ || request.MaxHeight.HasValue
+ || request.MaxWidth.HasValue)
{
outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
@@ -1463,12 +1548,15 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && outputSizeParam.Length == 0)
+ if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
+ && outputSizeParam.Length == 0)
{
outputSizeParam = ",format=nv12|vaapi,hwupload";
// Add parameters to use VAAPI with burn-in subttiles (GH issue #642)
- if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) {
+ if (state.SubtitleStream != null
+ && state.SubtitleStream.IsTextSubtitleStream
+ && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) {
outputSizeParam += ",hwmap=mode=read+write+direct";
}
}
@@ -1477,7 +1565,11 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue)
{
- videoSizeParam = string.Format("scale={0}:{1}", state.VideoStream.Width.Value.ToString(_usCulture), state.VideoStream.Height.Value.ToString(_usCulture));
+ videoSizeParam = string.Format(
+ CultureInfo.InvariantCulture,
+ "scale={0}:{1}",
+ state.VideoStream.Width.Value,
+ state.VideoStream.Height.Value);
videoSizeParam += ":force_original_aspect_ratio=decrease";
}
@@ -1490,15 +1582,18 @@ namespace MediaBrowser.Controller.MediaEncoding
? 0
: state.SubtitleStream.Index;
- return string.Format(" -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"",
- mapPrefix.ToString(_usCulture),
- subtitleStreamIndex.ToString(_usCulture),
- state.VideoStream.Index.ToString(_usCulture),
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"",
+ mapPrefix,
+ subtitleStreamIndex,
+ state.VideoStream.Index,
outputSizeParam,
videoSizeParam);
}
- private ValueTuple<int?, int?> GetFixedOutputSize(int? videoWidth,
+ private (int? width, int? height) GetFixedOutputSize(
+ int? videoWidth,
int? videoHeight,
int? requestedWidth,
int? requestedHeight,
@@ -1507,11 +1602,11 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (!videoWidth.HasValue && !requestedWidth.HasValue)
{
- return new ValueTuple<int?, int?>(null, null);
+ return (null, null);
}
if (!videoHeight.HasValue && !requestedHeight.HasValue)
{
- return new ValueTuple<int?, int?>(null, null);
+ return (null, null);
}
decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth);
@@ -1531,7 +1626,7 @@ namespace MediaBrowser.Controller.MediaEncoding
outputWidth = 2 * Math.Truncate(outputWidth / 2);
outputHeight = 2 * Math.Truncate(outputHeight / 2);
- return new ValueTuple<int?, int?>(Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight));
+ return (Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight));
}
public List<string> GetScalingFilters(int? videoWidth,
@@ -1545,9 +1640,17 @@ namespace MediaBrowser.Controller.MediaEncoding
int? requestedMaxHeight)
{
var filters = new List<string>();
- var fixedOutputSize = GetFixedOutputSize(videoWidth, videoHeight, requestedWidth, requestedHeight, requestedMaxWidth, requestedMaxHeight);
-
- if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue)
+ var (width, height) = GetFixedOutputSize(
+ videoWidth,
+ videoHeight,
+ requestedWidth,
+ requestedHeight,
+ requestedMaxWidth,
+ requestedMaxHeight);
+
+ if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
+ && width.HasValue
+ && height.HasValue)
{
// Work around vaapi's reduced scaling features
var scaler = "scale_vaapi";
@@ -1555,15 +1658,26 @@ namespace MediaBrowser.Controller.MediaEncoding
// Given the input dimensions (inputWidth, inputHeight), determine the output dimensions
// (outputWidth, outputHeight). The user may request precise output dimensions or maximum
// output dimensions. Output dimensions are guaranteed to be even.
- var outputWidth = fixedOutputSize.Item1.Value;
- var outputHeight = fixedOutputSize.Item2.Value;
+ var outputWidth = width.Value;
+ var outputHeight = height.Value;
- if (!videoWidth.HasValue || outputWidth != videoWidth.Value || !videoHeight.HasValue || outputHeight != videoHeight.Value)
+ if (!videoWidth.HasValue
+ || outputWidth != videoWidth.Value
+ || !videoHeight.HasValue
+ || outputHeight != videoHeight.Value)
{
- filters.Add(string.Format("{0}=w={1}:h={2}", scaler, outputWidth.ToString(_usCulture), outputHeight.ToString(_usCulture)));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}=w={1}:h={2}",
+ scaler,
+ outputWidth,
+ outputHeight));
}
}
- else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue)
+ else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1
+ && width.HasValue
+ && height.HasValue)
{
// Nothing to do, it's handled as an input resize filter
}
@@ -1579,7 +1693,12 @@ namespace MediaBrowser.Controller.MediaEncoding
var widthParam = requestedWidth.Value.ToString(_usCulture);
var heightParam = requestedHeight.Value.ToString(_usCulture);
- filters.Add(string.Format("scale=trunc({0}/64)*64:trunc({1}/2)*2", widthParam, heightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc({0}/64)*64:trunc({1}/2)*2",
+ widthParam,
+ heightParam));
}
else
{
@@ -1595,11 +1714,21 @@ namespace MediaBrowser.Controller.MediaEncoding
if (isExynosV4L2)
{
- filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/64)*64:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/64)*64:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2",
+ maxWidthParam,
+ maxHeightParam));
}
else
{
- filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2",
+ maxWidthParam,
+ maxHeightParam));
}
}
@@ -1615,7 +1744,11 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var widthParam = requestedWidth.Value.ToString(_usCulture);
- filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale={0}:trunc(ow/a/2)*2",
+ widthParam));
}
}
@@ -1626,11 +1759,19 @@ namespace MediaBrowser.Controller.MediaEncoding
if (isExynosV4L2)
{
- filters.Add(string.Format("scale=trunc(oh*a/64)*64:{0}", heightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(oh*a/64)*64:{0}",
+ heightParam));
}
else
{
- filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(oh*a/2)*2:{0}",
+ heightParam));
}
}
@@ -1641,11 +1782,19 @@ namespace MediaBrowser.Controller.MediaEncoding
if (isExynosV4L2)
{
- filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/64)*64:trunc(ow/dar/2)*2", maxWidthParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(min(max(iw\\,ih*dar)\\,{0})/64)*64:trunc(ow/dar/2)*2",
+ maxWidthParam));
}
else
{
- filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2",
+ maxWidthParam));
}
}
@@ -1656,11 +1805,19 @@ namespace MediaBrowser.Controller.MediaEncoding
if (isExynosV4L2)
{
- filters.Add(string.Format("scale=trunc(oh*a/64)*64:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(oh*a/64)*64:min(max(iw/dar\\,ih)\\,{0})",
+ maxHeightParam));
}
else
{
- filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})",
+ maxHeightParam));
}
}
}
@@ -1670,8 +1827,8 @@ namespace MediaBrowser.Controller.MediaEncoding
private string GetFixedSizeScalingFilter(Video3DFormat? threedFormat, int requestedWidth, int requestedHeight)
{
- var widthParam = requestedWidth.ToString(_usCulture);
- var heightParam = requestedHeight.ToString(_usCulture);
+ var widthParam = requestedWidth.ToString(CultureInfo.InvariantCulture);
+ var heightParam = requestedHeight.ToString(CultureInfo.InvariantCulture);
string filter = null;
@@ -1713,13 +1870,14 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- return string.Format(filter, widthParam, heightParam);
+ return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam);
}
/// <summary>
/// If we're going to put a fixed size on the command line, this will calculate it
/// </summary>
- public string GetOutputSizeParam(EncodingJobInfo state,
+ public string GetOutputSizeParam(
+ EncodingJobInfo state,
EncodingOptions options,
string outputVideoCodec,
bool allowTimeStampCopy = true)
@@ -1728,24 +1886,45 @@ namespace MediaBrowser.Controller.MediaEncoding
var request = state.BaseRequest;
+ var videoStream = state.VideoStream;
var filters = new List<string>();
+ // If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
+ var hwType = options.HardwareAccelerationType ?? string.Empty;
+ if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !options.EnableHardwareEncoding )
+ {
+ filters.Add("hwdownload");
+
+ // If transcoding from 10 bit, transform colour spaces too
+ if (!string.IsNullOrEmpty(videoStream.PixelFormat)
+ && videoStream.PixelFormat.IndexOf("p10", StringComparison.OrdinalIgnoreCase) != -1
+ && string.Equals(outputVideoCodec,"libx264", StringComparison.OrdinalIgnoreCase))
+ {
+ filters.Add("format=p010le");
+ filters.Add("format=nv12");
+ }
+ else
+ {
+ filters.Add("format=nv12");
+ }
+ }
+
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
- if (state.DeInterlace("h264", true) && string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ if (state.DeInterlace("h264", true)
+ && string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
- filters.Add(string.Format("deinterlace_vaapi"));
+ filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi"));
}
- var videoStream = state.VideoStream;
-
- if (state.DeInterlace("h264", true) && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
+ if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
+ && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
- var inputFramerate = videoStream == null ? null : videoStream.RealFrameRate;
+ var inputFramerate = videoStream?.RealFrameRate;
// If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
if (string.Equals(options.DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30)
@@ -1758,11 +1937,11 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- var inputWidth = videoStream == null ? null : videoStream.Width;
- var inputHeight = videoStream == null ? null : videoStream.Height;
+ var inputWidth = videoStream?.Width;
+ var inputHeight = videoStream?.Height;
var threeDFormat = state.MediaSource.Video3DFormat;
- var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, options);
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options);
filters.AddRange(GetScalingFilters(inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
@@ -1780,6 +1959,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
filters.Add("hwmap");
}
+
if (allowTimeStampCopy)
{
output += " -copyts";
@@ -1788,7 +1968,10 @@ namespace MediaBrowser.Controller.MediaEncoding
if (filters.Count > 0)
{
- output += string.Format(" -vf \"{0}\"", string.Join(",", filters.ToArray()));
+ output += string.Format(
+ CultureInfo.InvariantCulture,
+ " -vf \"{0}\"",
+ string.Join(",", filters));
}
return output;
@@ -1836,7 +2019,8 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- if (state.AudioStream != null && CanStreamCopyAudio(state, state.AudioStream, state.SupportedAudioCodecs))
+ if (state.AudioStream != null
+ && CanStreamCopyAudio(state, state.AudioStream, state.SupportedAudioCodecs))
{
state.OutputAudioCodec = "copy";
}
@@ -1853,14 +2037,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
public static string GetProbeSizeArgument(int numInputFiles)
- {
- return numInputFiles > 1 ? "-probesize 1G" : "";
- }
+ => numInputFiles > 1 ? "-probesize 1G" : "";
public static string GetAnalyzeDurationArgument(int numInputFiles)
- {
- return numInputFiles > 1 ? "-analyzeduration 200M" : "";
- }
+ => numInputFiles > 1 ? "-analyzeduration 200M" : "";
public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions)
{
@@ -1928,18 +2108,22 @@ namespace MediaBrowser.Controller.MediaEncoding
{
flags.Add("+igndts");
}
+
if (state.IgnoreInputIndex)
{
flags.Add("+ignidx");
}
+
if (state.GenPtsInput || string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
flags.Add("+genpts");
}
+
if (state.DiscardCorruptFramesInput)
{
flags.Add("+discardcorrupt");
}
+
if (state.EnableFastSeekInput)
{
flags.Add("+fastseek");
@@ -1947,24 +2131,33 @@ namespace MediaBrowser.Controller.MediaEncoding
if (flags.Count > 0)
{
- inputModifier += " -fflags " + string.Join("", flags.ToArray());
+ inputModifier += " -fflags " + string.Join(string.Empty, flags);
}
- var videoDecoder = this.GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions);
if (!string.IsNullOrEmpty(videoDecoder))
{
inputModifier += " " + videoDecoder;
- var videoStream = state.VideoStream;
- var inputWidth = videoStream == null ? null : videoStream.Width;
- var inputHeight = videoStream == null ? null : videoStream.Height;
- var request = state.BaseRequest;
+ if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ var videoStream = state.VideoStream;
+ var inputWidth = videoStream?.Width;
+ var inputHeight = videoStream?.Height;
+ var request = state.BaseRequest;
- var fixedOutputSize = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
+ var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
- if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 && fixedOutputSize.Item1.HasValue && fixedOutputSize.Item2.HasValue)
- {
- inputModifier += string.Format(" -resize {0}x{1}", fixedOutputSize.Item1.Value.ToString(_usCulture), fixedOutputSize.Item2.Value.ToString(_usCulture));
+ if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1
+ && width.HasValue
+ && height.HasValue)
+ {
+ inputModifier += string.Format(
+ CultureInfo.InvariantCulture,
+ " -resize {0}x{1}",
+ width.Value,
+ height.Value);
+ }
}
}
@@ -1973,9 +2166,9 @@ namespace MediaBrowser.Controller.MediaEncoding
var outputVideoCodec = GetVideoEncoder(state, encodingOptions);
// Important: If this is ever re-enabled, make sure not to use it with wtv because it breaks seeking
- if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase) &&
- state.TranscodingType != TranscodingJobType.Progressive &&
- state.EnableBreakOnNonKeyFrames(outputVideoCodec))
+ if (!string.Equals(state.InputContainer, "wtv", StringComparison.OrdinalIgnoreCase)
+ && state.TranscodingType != TranscodingJobType.Progressive
+ && state.EnableBreakOnNonKeyFrames(outputVideoCodec))
{
inputModifier += " -noaccurate_seek";
}
@@ -1999,14 +2192,16 @@ namespace MediaBrowser.Controller.MediaEncoding
}
- public void AttachMediaSourceInfo(EncodingJobInfo state,
- MediaSourceInfo mediaSource,
- string requestedUrl)
+ public void AttachMediaSourceInfo(
+ EncodingJobInfo state,
+ MediaSourceInfo mediaSource,
+ string requestedUrl)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
+
if (mediaSource == null)
{
throw new ArgumentNullException(nameof(mediaSource));
@@ -2064,15 +2259,16 @@ namespace MediaBrowser.Controller.MediaEncoding
state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
- if (state.ReadInputAtNativeFramerate ||
- mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
+ if (state.ReadInputAtNativeFramerate
+ || mediaSource.Protocol == MediaProtocol.File
+ && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
{
state.InputVideoSync = "-1";
state.InputAudioSync = "1";
}
- if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(mediaSource.Container, "asf", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(mediaSource.Container, "asf", StringComparison.OrdinalIgnoreCase))
{
// Seeing some stuttering when transcoding wma to audio-only HLS
state.InputAudioSync = "1";
@@ -2184,7 +2380,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
- return this.GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions);
+ return GetHardwareAcceleratedVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions);
}
public string GetHardwareAcceleratedVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions)
@@ -2197,9 +2393,9 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
- if (videoStream != null &&
- !string.IsNullOrEmpty(videoStream.Codec) &&
- !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType))
+ if (videoStream != null
+ && !string.IsNullOrEmpty(videoStream.Codec)
+ && !string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType))
{
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
@@ -2349,7 +2545,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
- return "-hwaccel dxva2";
+ if(Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1))
+ return "-hwaccel d3d11va";
+ else
+ return "-hwaccel dxva2";
}
switch (videoStream.Codec.ToLowerInvariant())
@@ -2397,14 +2596,10 @@ namespace MediaBrowser.Controller.MediaEncoding
codec = format;
}
- var args = " -codec:s:0 " + codec;
-
- args += " -disposition:s:0 default";
-
- return args;
+ return " -codec:s:0 " + codec + " -disposition:s:0 default";
}
- public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultH264Preset)
+ public string GetProgressiveVideoFullCommandLine(EncodingJobInfo state, EncodingOptions encodingOptions, string outputPath, string defaultPreset)
{
// Get the output codec name
var videoCodec = GetVideoEncoder(state, encodingOptions);
@@ -2412,8 +2607,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var format = string.Empty;
var keyFrame = string.Empty;
- if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase) &&
- state.BaseRequest.Context == EncodingContext.Streaming)
+ if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase)
+ && state.BaseRequest.Context == EncodingContext.Streaming)
{
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
format = " -f mp4 -movflags frag_keyframe+empty_moov";
@@ -2423,18 +2618,19 @@ namespace MediaBrowser.Controller.MediaEncoding
var inputModifier = GetInputModifier(state, encodingOptions);
- return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7}{8} -y \"{9}\"",
inputModifier,
GetInputArgument(state, encodingOptions),
keyFrame,
GetMapArgs(state),
- GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultH264Preset),
+ GetProgressiveVideoArguments(state, encodingOptions, videoCodec, defaultPreset),
threads,
GetProgressiveVideoAudioArguments(state, encodingOptions),
GetSubtitleEmbedArguments(state),
format,
- outputPath
- ).Trim();
+ outputPath).Trim();
}
public string GetOutputFFlags(EncodingJobInfo state)
@@ -2447,13 +2643,13 @@ namespace MediaBrowser.Controller.MediaEncoding
if (flags.Count > 0)
{
- return " -fflags " + string.Join("", flags.ToArray());
+ return " -fflags " + string.Join("", flags);
}
return string.Empty;
}
- public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultH264Preset)
+ public string GetProgressiveVideoArguments(EncodingJobInfo state, EncodingOptions encodingOptions, string videoCodec, string defaultPreset)
{
var args = "-codec:v:0 " + videoCodec;
@@ -2464,11 +2660,15 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase))
{
- if (state.VideoStream != null && IsH264(state.VideoStream) &&
- string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) &&
- !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
+ if (state.VideoStream != null
+ && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(state.VideoStream.NalLengthSize, "0", StringComparison.OrdinalIgnoreCase))
{
- args += " -bsf:v h264_mp4toannexb";
+ string bitStreamArgs = GetBitStreamArgs(state.VideoStream);
+ if (!string.IsNullOrEmpty(bitStreamArgs))
+ {
+ args += " " + bitStreamArgs;
+ }
}
if (state.RunTimeTicks.HasValue && state.BaseRequest.CopyTimestamps)
@@ -2483,8 +2683,10 @@ namespace MediaBrowser.Controller.MediaEncoding
}
else
{
- var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
- 5.ToString(_usCulture));
+ var keyFrameArg = string.Format(
+ CultureInfo.InvariantCulture,
+ " -force_key_frames \"expr:gte(t,n_forced*{0})\"",
+ 5);
args += keyFrameArg;
@@ -2505,6 +2707,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
args += " -copyts";
}
+
args += " -avoid_negative_ts disabled -start_at_zero";
}
@@ -2514,7 +2717,7 @@ namespace MediaBrowser.Controller.MediaEncoding
args += GetGraphicalSubtitleParam(state, encodingOptions, videoCodec);
}
- var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultH264Preset);
+ var qualityParam = GetVideoQualityParam(state, videoCodec, encodingOptions, defaultPreset);
if (!string.IsNullOrEmpty(qualityParam))
{
@@ -2605,39 +2808,22 @@ namespace MediaBrowser.Controller.MediaEncoding
}
}
- var albumCoverInput = string.Empty;
- var mapArgs = string.Empty;
- var metadata = string.Empty;
- var vn = string.Empty;
-
- var hasArt = !string.IsNullOrEmpty(state.AlbumCoverPath);
- hasArt = false;
-
- if (hasArt)
- {
- albumCoverInput = " -i \"" + state.AlbumCoverPath + "\"";
- mapArgs = " -map 0:a -map 1:v -c:1:v copy";
- metadata = " -metadata:s:v title=\"Album cover\" -metadata:s:v comment=\"Cover(Front)\"";
- }
- else
- {
- vn = " -vn";
- }
-
var threads = GetNumberOfThreads(state, encodingOptions, null);
var inputModifier = GetInputModifier(state, encodingOptions);
- return string.Format("{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} {1}{7}{8} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1{6} -y \"{5}\"",
inputModifier,
GetInputArgument(state, encodingOptions),
threads,
- vn,
- string.Join(" ", audioTranscodeParams.ToArray()),
+ " -vn",
+ string.Join(" ", audioTranscodeParams),
outputPath,
- metadata,
- albumCoverInput,
- mapArgs).Trim();
+ string.Empty,
+ string.Empty,
+ string.Empty).Trim();
}
}
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index be97c75a2..d64feb2f7 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -118,14 +118,14 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the profile.
/// </summary>
/// <value>The profile.</value>
- [ApiMember(Name = "Profile", Description = "Optional. Specify a specific h264 profile, e.g. main, baseline, high.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "Profile", Description = "Optional. Specify a specific an encoder profile (varies by encoder), e.g. main, baseline, high.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Profile { get; set; }
/// <summary>
/// Gets or sets the level.
/// </summary>
/// <value>The level.</value>
- [ApiMember(Name = "Level", Description = "Optional. Specify a level for the h264 profile, e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "Level", Description = "Optional. Specify a level for the encoder profile (varies by encoder), e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Level { get; set; }
/// <summary>
@@ -212,7 +212,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the video codec.
/// </summary>
/// <value>The video codec.</value>
- [ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h265, h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string VideoCodec { get; set; }
public string SubtitleCodec { get; set; }
diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
index 7f842c1d0..5cedc3d57 100644
--- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
+++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
@@ -1,8 +1,8 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Model.IO;
-using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -16,31 +16,26 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="videoPath">The video path.</param>
- /// <param name="protocol">The protocol.</param>
/// <param name="isoMount">The iso mount.</param>
/// <param name="playableStreamFileNames">The playable stream file names.</param>
- /// <returns>System.String[][].</returns>
- public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, MediaProtocol protocol, IIsoMount isoMount, string[] playableStreamFileNames)
+ /// <returns>string[].</returns>
+ public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, IIsoMount isoMount, IReadOnlyCollection<string> playableStreamFileNames)
{
- if (playableStreamFileNames.Length > 0)
+ if (playableStreamFileNames.Count > 0)
{
if (isoMount == null)
{
return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames);
}
+
return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames);
}
return new[] { videoPath };
}
- private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, string[] filenames)
+ private static string[] GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, IEnumerable<string> filenames)
{
- if (filenames.Length == 0)
- {
- return new string[] { };
- }
-
var allFiles = fileSystem
.GetFilePaths(rootPath, true)
.ToArray();
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
index 64c2294e3..29fb81e32 100644
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
@@ -1,5 +1,6 @@
using System;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
{
@@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="request">The http request wrapper</param>
/// <param name="response">The http response wrapper</param>
/// <param name="requestDto">The request DTO</param>
- public void RequestFilter(IRequest request, IResponse response, object requestDto)
+ public void RequestFilter(IRequest request, HttpResponse response, object requestDto)
{
AuthService.Authenticate(request, this);
}
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index e83260725..b45043f92 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Dto;
@@ -9,7 +11,6 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Playlists
{
@@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Playlists
Shares = Array.Empty<Share>();
}
- [IgnoreDataMember]
+ [JsonIgnore]
public bool IsFile => IsPlaylistFile(Path);
public static bool IsPlaylistFile(string path)
@@ -41,7 +42,7 @@ namespace MediaBrowser.Controller.Playlists
return System.IO.Path.HasExtension(path);
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override string ContainingFolderPath
{
get
@@ -57,19 +58,19 @@ namespace MediaBrowser.Controller.Playlists
}
}
- [IgnoreDataMember]
+ [JsonIgnore]
protected override bool FilterLinkedChildrenPerUser => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsInheritedParentImages => false;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsPlayedStatus => string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool AlwaysScanInternalMetadataPath => true;
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool SupportsCumulativeRunTimeTicks => true;
public override double GetDefaultPrimaryImageAspectRatio()
@@ -192,12 +193,12 @@ namespace MediaBrowser.Controller.Playlists
return new[] { item };
}
- [IgnoreDataMember]
+ [JsonIgnore]
public override bool IsPreSorted => true;
public string PlaylistMediaType { get; set; }
- [IgnoreDataMember]
+ [JsonIgnore]
public override string MediaType => PlaylistMediaType;
public void SetMediaType(string value)
@@ -205,7 +206,7 @@ namespace MediaBrowser.Controller.Playlists
PlaylistMediaType = value;
}
- [IgnoreDataMember]
+ [JsonIgnore]
private bool IsSharedItem
{
get
@@ -239,7 +240,7 @@ namespace MediaBrowser.Controller.Playlists
return base.IsVisible(user);
}
- var userId = user.Id.ToString("N");
+ var userId = user.Id.ToString("N", CultureInfo.InvariantCulture);
foreach (var share in shares)
{
if (string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs
index b0b443fc0..ac6b86c1d 100644
--- a/MediaBrowser.Controller/Providers/AlbumInfo.cs
+++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Providers
/// Gets or sets the album artist.
/// </summary>
/// <value>The album artist.</value>
- public string[] AlbumArtists { get; set; }
+ public IReadOnlyList<string> AlbumArtists { get; set; }
/// <summary>
/// Gets or sets the artist provider ids.
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
index f4b915c06..ebff81b7f 100644
--- a/MediaBrowser.Controller/Providers/MetadataResult.cs
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Providers
@@ -55,7 +56,7 @@ namespace MediaBrowser.Controller.Providers
foreach (var i in UserDataList)
{
- if (string.Equals(userId, i.UserId.ToString("N"), StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(userId, i.UserId.ToString("N", CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase))
{
userData = i;
}
diff --git a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
index 194b26484..9835351fc 100644
--- a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
+++ b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
@@ -1,7 +1,9 @@
+using System.Collections.Generic;
+
namespace MediaBrowser.Controller.Providers
{
public class MusicVideoInfo : ItemLookupInfo
{
- public string[] Artists { get; set; }
+ public IReadOnlyList<string> Artists { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs
index 61e950130..50615b0bd 100644
--- a/MediaBrowser.Controller/Providers/SongInfo.cs
+++ b/MediaBrowser.Controller/Providers/SongInfo.cs
@@ -1,12 +1,15 @@
using System;
+using System.Collections.Generic;
namespace MediaBrowser.Controller.Providers
{
public class SongInfo : ItemLookupInfo
{
- public string[] AlbumArtists { get; set; }
+ public IReadOnlyList<string> AlbumArtists { get; set; }
+
public string Album { get; set; }
- public string[] Artists { get; set; }
+
+ public IReadOnlyList<string> Artists { get; set; }
public SongInfo()
{
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index f0e81e8e7..acda6a416 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
+using System.Text.Json.Serialization;
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
@@ -123,7 +123,7 @@ namespace MediaBrowser.Controller.Session
/// Gets or sets the session controller.
/// </summary>
/// <value>The session controller.</value>
- [IgnoreDataMember]
+ [JsonIgnore]
public ISessionController[] SessionControllers { get; set; }
/// <summary>