aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Channels/InternalChannelFeatures.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs1
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs62
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs1
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs1
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs1
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs1
-rw-r--r--MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs6
-rw-r--r--MediaBrowser.Controller/Extensions/StringExtensions.cs6
-rw-r--r--MediaBrowser.Controller/IDisplayPreferencesManager.cs11
-rw-r--r--MediaBrowser.Controller/IO/FileData.cs1
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs7
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs4
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs1
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs3
-rw-r--r--MediaBrowser.Controller/LiveTv/ChannelInfo.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ProgramInfo.cs7
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingInfo.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerInfo.cs1
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj14
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs234
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs2
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs30
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs76
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs27
-rw-r--r--MediaBrowser.Controller/Net/IAuthService.cs17
-rw-r--r--MediaBrowser.Controller/Net/IAuthorizationContext.cs10
-rw-r--r--MediaBrowser.Controller/Net/IHasResultFactory.cs17
-rw-r--r--MediaBrowser.Controller/Net/IHttpResultFactory.cs82
-rw-r--r--MediaBrowser.Controller/Net/IHttpServer.cs50
-rw-r--r--MediaBrowser.Controller/Net/ISessionContext.cs6
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketManager.cs32
-rw-r--r--MediaBrowser.Controller/Net/StaticResultOptions.cs44
-rw-r--r--MediaBrowser.Controller/Persistence/IItemRepository.cs1
-rw-r--r--MediaBrowser.Controller/Providers/DirectoryService.cs44
-rw-r--r--MediaBrowser.Controller/Providers/ItemLookupInfo.cs6
-rw-r--r--MediaBrowser.Controller/QuickConnect/IQuickConnect.cs87
-rw-r--r--MediaBrowser.Controller/Resolvers/IItemResolver.cs1
-rw-r--r--MediaBrowser.Controller/Session/ISessionController.cs3
-rw-r--r--MediaBrowser.Controller/Session/ISessionManager.cs16
-rw-r--r--MediaBrowser.Controller/Session/SessionInfo.cs5
-rw-r--r--MediaBrowser.Controller/SyncPlay/GroupInfo.cs52
47 files changed, 462 insertions, 519 deletions
diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
index 1074ce435..137f5d095 100644
--- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
+++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Controller.Channels
/// Indicates if a sort ascending/descending toggle is supported or not.
/// </summary>
public bool SupportsSortOrderToggle { get; set; }
+
/// <summary>
/// Gets or sets the automatic refresh levels.
/// </summary>
@@ -53,6 +54,7 @@ namespace MediaBrowser.Controller.Channels
/// </summary>
/// <value>The daily download limit.</value>
public int? DailyDownloadLimit { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether [supports downloading].
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 2c6dea02c..8220464b3 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -90,7 +90,6 @@ namespace MediaBrowser.Controller.Entities.Audio
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty;
-
if (ParentIndexNumber.HasValue)
{
songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey;
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 24978d8dd..2fc7d45c9 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -60,8 +60,6 @@ namespace MediaBrowser.Controller.Entities
protected BaseItem()
{
- ThemeSongIds = Array.Empty<Guid>();
- ThemeVideoIds = Array.Empty<Guid>();
Tags = Array.Empty<string>();
Genres = Array.Empty<string>();
Studios = Array.Empty<string>();
@@ -100,12 +98,52 @@ namespace MediaBrowser.Controller.Entities
};
[JsonIgnore]
- public Guid[] ThemeSongIds { get; set; }
+ public Guid[] ThemeSongIds
+ {
+ get
+ {
+ if (_themeSongIds == null)
+ {
+ _themeSongIds = GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeSong)
+ .Select(song => song.Id)
+ .ToArray();
+ }
+
+ return _themeSongIds;
+ }
+
+ private set
+ {
+ _themeSongIds = value;
+ }
+ }
+
[JsonIgnore]
- public Guid[] ThemeVideoIds { get; set; }
+ public Guid[] ThemeVideoIds
+ {
+ get
+ {
+ if (_themeVideoIds == null)
+ {
+ _themeVideoIds = GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeVideo)
+ .Select(song => song.Id)
+ .ToArray();
+ }
+
+ return _themeVideoIds;
+ }
+
+ private set
+ {
+ _themeVideoIds = value;
+ }
+ }
[JsonIgnore]
public string PreferredMetadataCountryCode { get; set; }
+
[JsonIgnore]
public string PreferredMetadataLanguage { get; set; }
@@ -159,6 +197,7 @@ namespace MediaBrowser.Controller.Entities
public virtual bool SupportsRemoteImageDownloading => true;
private string _name;
+
/// <summary>
/// Gets or sets the name.
/// </summary>
@@ -623,6 +662,7 @@ namespace MediaBrowser.Controller.Entities
}
private string _forcedSortName;
+
/// <summary>
/// Gets or sets the name of the forced sort.
/// </summary>
@@ -635,6 +675,9 @@ namespace MediaBrowser.Controller.Entities
}
private string _sortName;
+ private Guid[] _themeSongIds;
+ private Guid[] _themeVideoIds;
+
/// <summary>
/// Gets the name of the sort.
/// </summary>
@@ -1582,7 +1625,8 @@ namespace MediaBrowser.Controller.Entities
await Task.WhenAll(tasks).ConfigureAwait(false);
- item.ThemeVideoIds = newThemeVideoIds;
+ // They are expected to be sorted by SortName
+ item.ThemeVideoIds = newThemeVideos.OrderBy(i => i.SortName).Select(i => i.Id).ToArray();
return themeVideosChanged;
}
@@ -1619,7 +1663,8 @@ namespace MediaBrowser.Controller.Entities
await Task.WhenAll(tasks).ConfigureAwait(false);
- item.ThemeSongIds = newThemeSongIds;
+ // They are expected to be sorted by SortName
+ item.ThemeSongIds = newThemeSongs.OrderBy(i => i.SortName).Select(i => i.Id).ToArray();
return themeSongsChanged;
}
@@ -2633,6 +2678,7 @@ namespace MediaBrowser.Controller.Entities
{
return new T
{
+ Path = Path,
MetadataCountryCode = GetPreferredMetadataCountryCode(),
MetadataLanguage = GetPreferredMetadataLanguage(),
Name = GetNameForMetadataLookup(),
@@ -2909,12 +2955,12 @@ namespace MediaBrowser.Controller.Entities
public IEnumerable<BaseItem> GetThemeSongs()
{
- return ThemeVideoIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeSong)).OrderBy(i => i.SortName);
+ return ThemeSongIds.Select(LibraryManager.GetItemById);
}
public IEnumerable<BaseItem> GetThemeVideos()
{
- return ThemeVideoIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeVideo)).OrderBy(i => i.SortName);
+ return ThemeVideoIds.Select(LibraryManager.GetItemById);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 11542c1ca..901ea875b 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1386,7 +1386,6 @@ namespace MediaBrowser.Controller.Entities
}
}
-
/// <summary>
/// Gets the linked children.
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index a7b60d168..0f612262a 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -21,7 +21,5 @@ namespace MediaBrowser.Controller.Entities
List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
List<MediaStream> GetMediaStreams();
-
-
}
}
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 1485d4c79..2fc66176f 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -16,7 +16,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override Folder LatestItemsIndexContainer => AlbumEntity;
-
[JsonIgnore]
public PhotoAlbum AlbumEntity
{
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 72c696c1a..75a746bfb 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -450,7 +450,6 @@ namespace MediaBrowser.Controller.Entities.TV
});
}
-
protected override bool GetBlockUnratedValue(User user)
{
return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Series.ToString());
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index b384b27d1..068a76769 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -258,7 +258,6 @@ namespace MediaBrowser.Controller.Entities
IncludeItemTypes = new[] { typeof(Movie).Name },
Recursive = true,
EnableTotalRecordCount = false
-
}).Items
.SelectMany(i => i.Genres)
.DistinctNames()
diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
index 4c2209b67..f9285c768 100644
--- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs
@@ -9,6 +9,12 @@ namespace MediaBrowser.Controller.Extensions
public static class ConfigurationExtensions
{
/// <summary>
+ /// The key for a setting that specifies the default redirect path
+ /// to use for requests where the URL base prefix is invalid or missing..
+ /// </summary>
+ public const string DefaultRedirectKey = "DefaultRedirectPath";
+
+ /// <summary>
/// The key for a setting that indicates whether the application should host web client content.
/// </summary>
public const string HostWebClientKey = "hostwebclient";
diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs
index 3cc1f328a..182c8ef65 100644
--- a/MediaBrowser.Controller/Extensions/StringExtensions.cs
+++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs
@@ -1,3 +1,4 @@
+#nullable enable
#pragma warning disable CS1591
using System;
@@ -15,11 +16,6 @@ namespace MediaBrowser.Controller.Extensions
{
public static string RemoveDiacritics(this string text)
{
- if (text == null)
- {
- throw new ArgumentNullException(nameof(text));
- }
-
var chars = Normalize(text, NormalizationForm.FormD)
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
index 856b91b5d..b35f83096 100644
--- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs
+++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
@@ -35,15 +35,8 @@ namespace MediaBrowser.Controller
IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client);
/// <summary>
- /// Saves changes to the provided display preferences.
+ /// Saves changes made to the database.
/// </summary>
- /// <param name="preferences">The display preferences to save.</param>
- void SaveChanges(DisplayPreferences preferences);
-
- /// <summary>
- /// Saves changes to the provided item display preferences.
- /// </summary>
- /// <param name="preferences">The item display preferences to save.</param>
- void SaveChanges(ItemDisplayPreferences preferences);
+ void SaveChanges();
}
}
diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs
index 9bc4cac39..3db60ae0b 100644
--- a/MediaBrowser.Controller/IO/FileData.cs
+++ b/MediaBrowser.Controller/IO/FileData.cs
@@ -111,5 +111,4 @@ namespace MediaBrowser.Controller.IO
return returnResult;
}
}
-
}
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 39b896c0f..cfad17fb7 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -20,6 +20,8 @@ namespace MediaBrowser.Controller
IServiceProvider ServiceProvider { get; }
+ bool CoreStartupHasCompleted { get; }
+
bool CanLaunchWebBrowser { get; }
/// <summary>
@@ -112,13 +114,10 @@ namespace MediaBrowser.Controller
/// <exception cref="NotSupportedException"><see cref="CanLaunchWebBrowser"/> is false.</exception>
void LaunchUrl(string url);
- void EnableLoopback(string appName);
-
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
string ExpandVirtualPath(string path);
- string ReverseVirtualPath(string path);
- Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next);
+ string ReverseVirtualPath(string path);
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index d2f937d4f..332730bcc 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -77,6 +77,7 @@ namespace MediaBrowser.Controller.Library
MusicArtist GetArtist(string name);
MusicArtist GetArtist(string name, DtoOptions options);
+
/// <summary>
/// Gets a Studio.
/// </summary>
@@ -200,7 +201,7 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Creates the items.
/// </summary>
- void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
+ void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
/// <summary>
/// Updates the item.
@@ -234,6 +235,7 @@ namespace MediaBrowser.Controller.Library
/// Occurs when [item updated].
/// </summary>
event EventHandler<ItemChangeEventArgs> ItemUpdated;
+
/// <summary>
/// Occurs when [item removed].
/// </summary>
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 9e7b1e608..22bf9488f 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -28,12 +28,14 @@ namespace MediaBrowser.Controller.Library
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
List<MediaStream> GetMediaStreams(Guid itemId);
+
/// <summary>
/// Gets the media streams.
/// </summary>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
List<MediaStream> GetMediaStreams(string mediaSourceId);
+
/// <summary>
/// Gets the media streams.
/// </summary>
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
index 6a0dbeba2..12a311dc3 100644
--- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -156,6 +156,7 @@ namespace MediaBrowser.Controller.Library
}
// REVIEW: @bond
+
/// <summary>
/// Gets the physical locations.
/// </summary>
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
index 21f33ad19..1c90bb4e0 100644
--- a/MediaBrowser.Controller/Library/NameExtensions.cs
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -1,3 +1,4 @@
+#nullable enable
#pragma warning disable CS1591
using System;
@@ -9,7 +10,7 @@ namespace MediaBrowser.Controller.Library
{
public static class NameExtensions
{
- private static string RemoveDiacritics(string name)
+ private static string RemoveDiacritics(string? name)
{
if (name == null)
{
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
index d7afd2118..44bd38b54 100644
--- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
public bool? HasImage { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether this instance is favorite.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 55c330931..6c365caa4 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -231,6 +231,7 @@ namespace MediaBrowser.Controller.LiveTv
/// Saves the tuner host.
/// </summary>
Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true);
+
/// <summary>
/// Saves the listing provider.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index ff92bf856..abca8f239 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -56,7 +56,6 @@ namespace MediaBrowser.Controller.LiveTv
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken);
-
}
public interface IConfigurableTunerHost
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
index 02178297b..b62974904 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value>The tuners.</value>
public List<LiveTvTunerInfo> Tuners { get; set; }
+
/// <summary>
/// Gets or sets a value indicating whether this instance is visible.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
index bdcffd5ca..f9f559ee9 100644
--- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
@@ -35,6 +35,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value>The overview.</value>
public string Overview { get; set; }
+
/// <summary>
/// Gets or sets the short overview.
/// </summary>
@@ -169,31 +170,37 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value>The production year.</value>
public int? ProductionYear { get; set; }
+
/// <summary>
/// Gets or sets the home page URL.
/// </summary>
/// <value>The home page URL.</value>
public string HomePageUrl { get; set; }
+
/// <summary>
/// Gets or sets the series identifier.
/// </summary>
/// <value>The series identifier.</value>
public string SeriesId { get; set; }
+
/// <summary>
/// Gets or sets the show identifier.
/// </summary>
/// <value>The show identifier.</value>
public string ShowId { get; set; }
+
/// <summary>
/// Gets or sets the season number.
/// </summary>
/// <value>The season number.</value>
public int? SeasonNumber { get; set; }
+
/// <summary>
/// Gets or sets the episode number.
/// </summary>
/// <value>The episode number.</value>
public int? EpisodeNumber { get; set; }
+
/// <summary>
/// Gets or sets the etag.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
index 303882b7e..69190694f 100644
--- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
@@ -187,6 +187,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
public bool? HasImage { get; set; }
+
/// <summary>
/// Gets or sets the show identifier.
/// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
index bcef4666d..aa5170617 100644
--- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -113,6 +113,7 @@ namespace MediaBrowser.Controller.LiveTv
// Program properties
public int? SeasonNumber { get; set; }
+
/// <summary>
/// Gets or sets the episode number.
/// </summary>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index df92eda38..654470406 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -14,8 +14,9 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" />
- <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.6" />
+ <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
+ <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.8" />
+ <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
@@ -32,6 +33,15 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
+ <PublishRepositoryUrl>true</PublishRepositoryUrl>
+ <EmbedUntrackedSources>true</EmbedUntrackedSources>
+ <IncludeSymbols>true</IncludeSymbols>
+ <SymbolPackageFormat>snupkg</SymbolPackageFormat>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(Stability)'=='Unstable'">
+ <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. -->
+ <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<!-- Code Analyzers-->
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 550916f82..c5529ad5b 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -109,7 +109,6 @@ namespace MediaBrowser.Controller.MediaEncoding
}
return _mediaEncoder.SupportsHwaccel("vaapi");
-
}
/// <summary>
@@ -456,6 +455,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvencHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
@@ -507,6 +507,7 @@ namespace MediaBrowser.Controller.MediaEncoding
arg.Append("-hwaccel qsv ");
}
}
+
// While using SW decoder
else
{
@@ -516,6 +517,24 @@ namespace MediaBrowser.Controller.MediaEncoding
}
if (state.IsVideoRequest
+ && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ var isColorDepth10 = IsColorDepth10(state);
+
+ if (isNvencHevcDecoder && isColorDepth10
+ && _mediaEncoder.SupportsHwaccel("opencl")
+ && encodingOptions.EnableTonemapping
+ && !string.IsNullOrEmpty(state.VideoStream.VideoRange)
+ && state.VideoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
+ {
+ arg.Append("-init_hw_device opencl=ocl:")
+ .Append(encodingOptions.OpenclDevice)
+ .Append(' ')
+ .Append("-filter_hw_device ocl ");
+ }
+ }
+
+ if (state.IsVideoRequest
&& string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
{
arg.Append("-hwaccel videotoolbox ");
@@ -1003,11 +1022,33 @@ namespace MediaBrowser.Controller.MediaEncoding
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_nvenc", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
+ if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
+ {
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
+ var videoStream = state.VideoStream;
+ var isColorDepth10 = IsColorDepth10(state);
+
+ if (videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1
+ && isColorDepth10
+ && _mediaEncoder.SupportsHwaccel("opencl")
+ && encodingOptions.EnableTonemapping
+ && !string.IsNullOrEmpty(videoStream.VideoRange)
+ && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
+ {
+ param = "-pix_fmt nv12 " + param;
+ }
+ else
+ {
+ param = "-pix_fmt yuv420p " + param;
+ }
+ }
+
if (string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt nv21 " + param;
@@ -1400,7 +1441,6 @@ namespace MediaBrowser.Controller.MediaEncoding
var codec = outputAudioCodec ?? string.Empty;
-
int? transcoderChannelLimit;
if (codec.IndexOf("wma", StringComparison.OrdinalIgnoreCase) != -1)
{
@@ -1611,64 +1651,45 @@ namespace MediaBrowser.Controller.MediaEncoding
var outputSizeParam = ReadOnlySpan<char>.Empty;
var request = state.BaseRequest;
- // Add resolution params, if specified
- if (request.Width.HasValue
- || request.Height.HasValue
- || request.MaxHeight.HasValue
- || request.MaxWidth.HasValue)
+ outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
+
+ // All possible beginning of video filters
+ // Don't break the order
+ string[] beginOfOutputSizeParam = new[]
{
- outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
+ // for tonemap_opencl
+ "hwupload,tonemap_opencl",
// hwupload=extra_hw_frames=64,vpp_qsv (for overlay_qsv on linux)
- var index = outputSizeParam.IndexOf("hwupload=extra_hw_frames", StringComparison.OrdinalIgnoreCase);
+ "hwupload=extra_hw_frames",
+
+ // vpp_qsv
+ "vpp",
+
+ // hwdownload,format=p010le (hardware decode + software encode for vaapi)
+ "hwdownload",
+
+ // format=nv12|vaapi,hwupload,scale_vaapi
+ "format",
+
+ // bwdif,scale=expr
+ "bwdif",
+
+ // yadif,scale=expr
+ "yadif",
+
+ // scale=expr
+ "scale"
+ };
+
+ var index = -1;
+ foreach (var param in beginOfOutputSizeParam)
+ {
+ index = outputSizeParam.IndexOf(param, StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
outputSizeParam = outputSizeParam.Slice(index);
- }
- else
- {
- // vpp_qsv
- index = outputSizeParam.IndexOf("vpp", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- outputSizeParam = outputSizeParam.Slice(index);
- }
- else
- {
- // hwdownload,format=p010le (hardware decode + software encode for vaapi)
- index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- outputSizeParam = outputSizeParam.Slice(index);
- }
- else
- {
- // format=nv12|vaapi,hwupload,scale_vaapi
- index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- outputSizeParam = outputSizeParam.Slice(index);
- }
- else
- {
- // yadif,scale=expr
- index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- outputSizeParam = outputSizeParam.Slice(index);
- }
- else
- {
- // scale=expr
- index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
- if (index != -1)
- {
- outputSizeParam = outputSizeParam.Slice(index);
- }
- }
- }
- }
- }
+ break;
}
}
@@ -1747,9 +1768,9 @@ namespace MediaBrowser.Controller.MediaEncoding
*/
if (isLinux)
{
- retStr = !outputSizeParam.IsEmpty ?
- " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" :
- " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
+ retStr = !outputSizeParam.IsEmpty
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\""
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
}
}
@@ -2084,12 +2105,61 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
var isNvdecH264Decoder = videoDecoder.IndexOf("h264_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
+ var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+ var isColorDepth10 = IsColorDepth10(state);
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+ // If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
+ var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
+
+ // Currently only with the use of NVENC decoder can we get a decent performance.
+ // Currently only the HEVC/H265 format is supported.
+ // NVIDIA Pascal and Turing or higher are recommended.
+ if (isNvdecHevcDecoder && isColorDepth10
+ && _mediaEncoder.SupportsHwaccel("opencl")
+ && options.EnableTonemapping
+ && !string.IsNullOrEmpty(videoStream.VideoRange)
+ && videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
+ {
+ var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
+
+ if (options.TonemappingParam != 0)
+ {
+ parameters += ":param={4}";
+ }
+
+ if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
+ {
+ parameters += ":range={5}";
+ }
+
+ // Upload the HDR10 or HLG data to the OpenCL device,
+ // use tonemap_opencl filter for tone mapping,
+ // and then download the SDR data to memory.
+ filters.Add("hwupload");
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ parameters,
+ options.TonemappingAlgorithm,
+ options.TonemappingDesat,
+ options.TonemappingThreshold,
+ options.TonemappingPeak,
+ options.TonemappingParam,
+ options.TonemappingRange));
+ filters.Add("hwdownload");
+
+ if (hasGraphicalSubs || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)
+ || string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
+ {
+ filters.Add("format=nv12");
+ }
+ }
+
// When the input may or may not be hardware VAAPI decodable
if (isVaapiH264Encoder)
{
@@ -2107,7 +2177,6 @@ namespace MediaBrowser.Controller.MediaEncoding
else if (IsVaapiSupported(state) && isVaapiDecoder && isLibX264Encoder)
{
var codec = videoStream.Codec.ToLowerInvariant();
- var isColorDepth10 = IsColorDepth10(state);
// Assert 10-bit hardware VAAPI decodable
if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
@@ -2136,35 +2205,38 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (isVaapiH264Encoder)
{
- filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi"));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "deinterlace_vaapi=rate={0}",
+ doubleRateDeinterlace ? "field" : "frame"));
}
}
// Add software deinterlace filter before scaling filter
- if (state.DeInterlace("h264", true)
- || state.DeInterlace("avc", true)
- || state.DeInterlace("h265", true)
- || state.DeInterlace("hevc", true))
+ if ((state.DeInterlace("h264", true)
+ || state.DeInterlace("avc", true)
+ || state.DeInterlace("h265", true)
+ || state.DeInterlace("hevc", true))
+ && !isVaapiH264Encoder
+ && !isQsvH264Encoder
+ && !isNvdecH264Decoder)
{
- string deintParam;
- 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, "yadif_bob", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30)
+ if (string.Equals(options.DeinterlaceMethod, "bwdif", StringComparison.OrdinalIgnoreCase))
{
- deintParam = "yadif=1:-1:0";
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "bwdif={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
else
{
- deintParam = "yadif=0:-1:0";
- }
-
- if (!string.IsNullOrEmpty(deintParam))
- {
- if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder)
- {
- filters.Add(deintParam);
- }
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
}
@@ -2397,6 +2469,11 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.DeInterlace("h264", true))
{
inputModifier += " -deint 1";
+
+ if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.RealFrameRate ?? 60) > 30)
+ {
+ inputModifier += " -drop_second_field 1";
+ }
}
}
}
@@ -2433,7 +2510,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return inputModifier;
}
-
public void AttachMediaSourceInfo(
EncodingJobInfo state,
MediaSourceInfo mediaSource,
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
index 68bc502a0..c7ec878d2 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs
@@ -697,10 +697,12 @@ namespace MediaBrowser.Controller.MediaEncoding
/// The progressive.
/// </summary>
Progressive,
+
/// <summary>
/// The HLS.
/// </summary>
Hls,
+
/// <summary>
/// The dash.
/// </summary>
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
index 4cbb63e46..1f3abe8f4 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs
@@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Services;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -63,26 +62,20 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public Guid Id { get; set; }
- [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string MediaSourceId { get; set; }
- [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; }
- [ApiMember(Name = "Container", Description = "Container", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Container { get; set; }
/// <summary>
/// Gets or sets the audio codec.
/// </summary>
/// <value>The audio codec.</value>
- [ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string AudioCodec { get; set; }
- [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool EnableAutoStreamCopy { get; set; }
public bool AllowVideoStreamCopy { get; set; }
@@ -95,7 +88,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the audio sample rate.
/// </summary>
/// <value>The audio sample rate.</value>
- [ApiMember(Name = "AudioSampleRate", Description = "Optional. Specify a specific audio sample rate, e.g. 44100", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? AudioSampleRate { get; set; }
public int? MaxAudioBitDepth { get; set; }
@@ -104,105 +96,86 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the audio bit rate.
/// </summary>
/// <value>The audio bit rate.</value>
- [ApiMember(Name = "AudioBitRate", Description = "Optional. Specify an audio bitrate to encode to, e.g. 128000. If omitted this will be left to encoder defaults.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? AudioBitRate { get; set; }
/// <summary>
/// Gets or sets the audio channels.
/// </summary>
/// <value>The audio channels.</value>
- [ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? AudioChannels { get; set; }
- [ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxAudioChannels { get; set; }
- [ApiMember(Name = "Static", Description = "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool Static { get; set; }
/// <summary>
/// Gets or sets the profile.
/// </summary>
/// <value>The profile.</value>
- [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 encoder profile (varies by encoder), e.g. 3, 3.1.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Level { get; set; }
/// <summary>
/// Gets or sets the framerate.
/// </summary>
/// <value>The framerate.</value>
- [ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public float? Framerate { get; set; }
- [ApiMember(Name = "MaxFramerate", Description = "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public float? MaxFramerate { get; set; }
- [ApiMember(Name = "CopyTimestamps", Description = "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool CopyTimestamps { get; set; }
/// <summary>
/// Gets or sets the start time ticks.
/// </summary>
/// <value>The start time ticks.</value>
- [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public long? StartTimeTicks { get; set; }
/// <summary>
/// Gets or sets the width.
/// </summary>
/// <value>The width.</value>
- [ApiMember(Name = "Width", Description = "Optional. The fixed horizontal resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Width { get; set; }
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
- [ApiMember(Name = "Height", Description = "Optional. The fixed vertical resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Height { get; set; }
/// <summary>
/// Gets or sets the width of the max.
/// </summary>
/// <value>The width of the max.</value>
- [ApiMember(Name = "MaxWidth", Description = "Optional. The maximum horizontal resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxWidth { get; set; }
/// <summary>
/// Gets or sets the height of the max.
/// </summary>
/// <value>The height of the max.</value>
- [ApiMember(Name = "MaxHeight", Description = "Optional. The maximum vertical resolution of the encoded video.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxHeight { get; set; }
/// <summary>
/// Gets or sets the video bit rate.
/// </summary>
/// <value>The video bit rate.</value>
- [ApiMember(Name = "VideoBitRate", Description = "Optional. Specify a video bitrate to encode to, e.g. 500000. If omitted this will be left to encoder defaults.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? VideoBitRate { get; set; }
/// <summary>
/// Gets or sets the index of the subtitle stream.
/// </summary>
/// <value>The index of the subtitle stream.</value>
- [ApiMember(Name = "SubtitleStreamIndex", Description = "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? SubtitleStreamIndex { get; set; }
- [ApiMember(Name = "SubtitleMethod", Description = "Optional. Specify the subtitle delivery method.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public SubtitleDeliveryMethod SubtitleMethod { get; set; }
- [ApiMember(Name = "MaxRefFrames", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxRefFrames { get; set; }
- [ApiMember(Name = "MaxVideoBitDepth", Description = "Optional.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxVideoBitDepth { get; set; }
public bool RequireAvc { get; set; }
@@ -223,7 +196,6 @@ 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: h265, h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string VideoCodec { get; set; }
public string SubtitleCodec { get; set; }
@@ -234,14 +206,12 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets or sets the index of the audio stream.
/// </summary>
/// <value>The index of the audio stream.</value>
- [ApiMember(Name = "AudioStreamIndex", Description = "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? AudioStreamIndex { get; set; }
/// <summary>
/// Gets or sets the index of the video stream.
/// </summary>
/// <value>The index of the video stream.</value>
- [ApiMember(Name = "VideoStreamIndex", Description = "Optional. The index of the video stream to use. If omitted the first video stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? VideoStreamIndex { get; set; }
public EncodingContext Context { get; set; }
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
deleted file mode 100644
index 1366fd42e..000000000
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using MediaBrowser.Model.Services;
-using Microsoft.AspNetCore.Http;
-
-namespace MediaBrowser.Controller.Net
-{
- public class AuthenticatedAttribute : Attribute, IHasRequestFilter, IAuthenticationAttributes
- {
- public static IAuthService AuthService { get; set; }
-
- /// <summary>
- /// Gets or sets the roles.
- /// </summary>
- /// <value>The roles.</value>
- public string Roles { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [escape parental control].
- /// </summary>
- /// <value><c>true</c> if [escape parental control]; otherwise, <c>false</c>.</value>
- public bool EscapeParentalControl { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether [allow before startup wizard].
- /// </summary>
- /// <value><c>true</c> if [allow before startup wizard]; otherwise, <c>false</c>.</value>
- public bool AllowBeforeStartupWizard { get; set; }
-
- public bool AllowLocal { get; set; }
-
- /// <summary>
- /// The request filter is executed before the service.
- /// </summary>
- /// <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, HttpResponse response, object requestDto)
- {
- AuthService.Authenticate(request, this);
- }
-
- /// <summary>
- /// Order in which Request Filters are executed.
- /// &lt;0 Executed before global request filters
- /// &gt;0 Executed after global request filters
- /// </summary>
- /// <value>The priority.</value>
- public int Priority => 0;
-
- public string[] GetRoles()
- {
- return (Roles ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- }
-
- public bool IgnoreLegacyAuth { get; set; }
-
- public bool AllowLocalOnly { get; set; }
- }
-
- public interface IAuthenticationAttributes
- {
- bool EscapeParentalControl { get; }
-
- bool AllowBeforeStartupWizard { get; }
-
- bool AllowLocal { get; }
-
- bool AllowLocalOnly { get; }
-
- string[] GetRoles();
-
- bool IgnoreLegacyAuth { get; }
- }
-}
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 916dea58b..28227603b 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -8,6 +8,7 @@ using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Net
@@ -28,10 +29,22 @@ namespace MediaBrowser.Controller.Net
new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>();
/// <summary>
- /// Gets the name.
+ /// Gets the type used for the messages sent to the client.
/// </summary>
- /// <value>The name.</value>
- protected abstract string Name { get; }
+ /// <value>The type.</value>
+ protected abstract SessionMessageType Type { get; }
+
+ /// <summary>
+ /// Gets the message type received from the client to start sending messages.
+ /// </summary>
+ /// <value>The type.</value>
+ protected abstract SessionMessageType StartType { get; }
+
+ /// <summary>
+ /// Gets the message type received from the client to stop sending messages.
+ /// </summary>
+ /// <value>The type.</value>
+ protected abstract SessionMessageType StopType { get; }
/// <summary>
/// Gets the data to send.
@@ -66,12 +79,12 @@ namespace MediaBrowser.Controller.Net
throw new ArgumentNullException(nameof(message));
}
- if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase))
+ if (message.MessageType == StartType)
{
Start(message);
}
- if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase))
+ if (message.MessageType == StopType)
{
Stop(message);
}
@@ -159,7 +172,7 @@ namespace MediaBrowser.Controller.Net
new WebSocketMessage<TReturnDataType>
{
MessageId = Guid.NewGuid(),
- MessageType = Name,
+ MessageType = Type,
Data = data
},
cancellationToken).ConfigureAwait(false);
@@ -176,7 +189,7 @@ namespace MediaBrowser.Controller.Net
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error sending web socket message {Name}", Name);
+ Logger.LogError(ex, "Error sending web socket message {Name}", Type);
DisposeConnection(tuple);
}
}
diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs
index 2055a656a..04b2e13e8 100644
--- a/MediaBrowser.Controller/Net/IAuthService.cs
+++ b/MediaBrowser.Controller/Net/IAuthService.cs
@@ -1,7 +1,5 @@
#nullable enable
-using Jellyfin.Data.Entities;
-using MediaBrowser.Model.Services;
using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
@@ -12,21 +10,6 @@ namespace MediaBrowser.Controller.Net
public interface IAuthService
{
/// <summary>
- /// Authenticate and authorize request.
- /// </summary>
- /// <param name="request">Request.</param>
- /// <param name="authAttribtutes">Authorization attributes.</param>
- void Authenticate(IRequest request, IAuthenticationAttributes authAttribtutes);
-
- /// <summary>
- /// Authenticate and authorize request.
- /// </summary>
- /// <param name="request">Request.</param>
- /// <param name="authAttribtutes">Authorization attributes.</param>
- /// <returns>Authenticated user.</returns>
- User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtutes);
-
- /// <summary>
/// Authenticate request.
/// </summary>
/// <param name="request">The request.</param>
diff --git a/MediaBrowser.Controller/Net/IAuthorizationContext.cs b/MediaBrowser.Controller/Net/IAuthorizationContext.cs
index 37a7425b9..0d310548d 100644
--- a/MediaBrowser.Controller/Net/IAuthorizationContext.cs
+++ b/MediaBrowser.Controller/Net/IAuthorizationContext.cs
@@ -1,4 +1,3 @@
-using MediaBrowser.Model.Services;
using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
@@ -13,14 +12,7 @@ namespace MediaBrowser.Controller.Net
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <returns>AuthorizationInfo.</returns>
- AuthorizationInfo GetAuthorizationInfo(object requestContext);
-
- /// <summary>
- /// Gets the authorization information.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <returns>AuthorizationInfo.</returns>
- AuthorizationInfo GetAuthorizationInfo(IRequest requestContext);
+ AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext);
/// <summary>
/// Gets the authorization information.
diff --git a/MediaBrowser.Controller/Net/IHasResultFactory.cs b/MediaBrowser.Controller/Net/IHasResultFactory.cs
deleted file mode 100644
index b8cf8cd78..000000000
--- a/MediaBrowser.Controller/Net/IHasResultFactory.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Controller.Net
-{
- /// <summary>
- /// Interface IHasResultFactory
- /// Services that require a ResultFactory should implement this
- /// </summary>
- public interface IHasResultFactory : IRequiresRequest
- {
- /// <summary>
- /// Gets or sets the result factory.
- /// </summary>
- /// <value>The result factory.</value>
- IHttpResultFactory ResultFactory { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
deleted file mode 100644
index 8293a8714..000000000
--- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Controller.Net
-{
- /// <summary>
- /// Interface IHttpResultFactory.
- /// </summary>
- public interface IHttpResultFactory
- {
- /// <summary>
- /// Gets the result.
- /// </summary>
- /// <param name="content">The content.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <returns>System.Object.</returns>
- object GetResult(string content, string contentType, IDictionary<string, string> responseHeaders = null);
-
- object GetResult(IRequest requestContext, byte[] content, string contentType, IDictionary<string, string> responseHeaders = null);
-
- object GetResult(IRequest requestContext, Stream content, string contentType, IDictionary<string, string> responseHeaders = null);
-
- object GetResult(IRequest requestContext, string content, string contentType, IDictionary<string, string> responseHeaders = null);
-
- object GetRedirectResult(string url);
-
- object GetResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null)
- where T : class;
-
- /// <summary>
- /// Gets the static result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="cacheKey">The cache key.</param>
- /// <param name="lastDateModified">The last date modified.</param>
- /// <param name="cacheDuration">Duration of the cache.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="factoryFn">The factory fn.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <returns>System.Object.</returns>
- Task<object> GetStaticResult(IRequest requestContext,
- Guid cacheKey,
- DateTime? lastDateModified,
- TimeSpan? cacheDuration,
- string contentType, Func<Task<Stream>> factoryFn,
- IDictionary<string, string> responseHeaders = null,
- bool isHeadRequest = false);
-
- /// <summary>
- /// Gets the static result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.Object.</returns>
- Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options);
-
- /// <summary>
- /// Gets the static file result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="path">The path.</param>
- /// <param name="fileShare">The file share.</param>
- /// <returns>System.Object.</returns>
- Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
-
- /// <summary>
- /// Gets the static file result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="options">The options.</param>
- /// <returns>System.Object.</returns>
- Task<object> GetStaticFileResult(IRequest requestContext,
- StaticFileResultOptions options);
- }
-}
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs
deleted file mode 100644
index b04ebda8c..000000000
--- a/MediaBrowser.Controller/Net/IHttpServer.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Jellyfin.Data.Events;
-using MediaBrowser.Model.Services;
-using Microsoft.AspNetCore.Http;
-
-namespace MediaBrowser.Controller.Net
-{
- /// <summary>
- /// Interface IHttpServer.
- /// </summary>
- public interface IHttpServer
- {
- /// <summary>
- /// Gets the URL prefix.
- /// </summary>
- /// <value>The URL prefix.</value>
- string[] UrlPrefixes { get; }
-
- /// <summary>
- /// Occurs when [web socket connected].
- /// </summary>
- event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
- /// <summary>
- /// Inits this instance.
- /// </summary>
- void Init(IEnumerable<Type> serviceTypes, IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes);
-
- /// <summary>
- /// If set, all requests will respond with this message.
- /// </summary>
- string GlobalResponse { get; set; }
-
- /// <summary>
- /// The HTTP request handler.
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- Task RequestHandler(HttpContext context);
-
- /// <summary>
- /// Get the default CORS headers.
- /// </summary>
- /// <param name="req"></param>
- /// <returns></returns>
- IDictionary<string, string> GetDefaultCorsHeaders(IRequest req);
- }
-}
diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs
index 5da748f41..a60dc2ea1 100644
--- a/MediaBrowser.Controller/Net/ISessionContext.cs
+++ b/MediaBrowser.Controller/Net/ISessionContext.cs
@@ -2,7 +2,7 @@
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
{
@@ -12,8 +12,8 @@ namespace MediaBrowser.Controller.Net
User GetUser(object requestContext);
- SessionInfo GetSession(IRequest requestContext);
+ SessionInfo GetSession(HttpContext requestContext);
- User GetUser(IRequest requestContext);
+ User GetUser(HttpContext requestContext);
}
}
diff --git a/MediaBrowser.Controller/Net/IWebSocketManager.cs b/MediaBrowser.Controller/Net/IWebSocketManager.cs
new file mode 100644
index 000000000..e9f00ae88
--- /dev/null
+++ b/MediaBrowser.Controller/Net/IWebSocketManager.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Jellyfin.Data.Events;
+using Microsoft.AspNetCore.Http;
+
+namespace MediaBrowser.Controller.Net
+{
+ /// <summary>
+ /// Interface IHttpServer.
+ /// </summary>
+ public interface IWebSocketManager
+ {
+ /// <summary>
+ /// Occurs when [web socket connected].
+ /// </summary>
+ event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
+
+ /// <summary>
+ /// Inits this instance.
+ /// </summary>
+ /// <param name="listeners">The websocket listeners.</param>
+ void Init(IEnumerable<IWebSocketListener> listeners);
+
+ /// <summary>
+ /// The HTTP request handler.
+ /// </summary>
+ /// <param name="context">The current HTTP context.</param>
+ /// <returns>The task.</returns>
+ Task WebSocketRequestHandler(HttpContext context);
+ }
+}
diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs
deleted file mode 100644
index c1e9bc845..000000000
--- a/MediaBrowser.Controller/Net/StaticResultOptions.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Net
-{
- public class StaticResultOptions
- {
- public string ContentType { get; set; }
-
- public TimeSpan? CacheDuration { get; set; }
-
- public DateTime? DateLastModified { get; set; }
-
- public Func<Task<Stream>> ContentFactory { get; set; }
-
- public bool IsHeadRequest { get; set; }
-
- public IDictionary<string, string> ResponseHeaders { get; set; }
-
- public Action OnComplete { get; set; }
-
- public Action OnError { get; set; }
-
- public string Path { get; set; }
-
- public long? ContentLength { get; set; }
-
- public FileShare FileShare { get; set; }
-
- public StaticResultOptions()
- {
- ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- FileShare = FileShare.Read;
- }
- }
-
- public class StaticFileResultOptions : StaticResultOptions
- {
- }
-}
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index ebc37bd1f..45c6805f0 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -100,6 +100,7 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="query">The query.</param>
/// <returns>IEnumerable&lt;Guid&gt;.</returns>
QueryResult<Guid> GetItemIds(InternalItemsQuery query);
+
/// <summary>
/// Gets the items.
/// </summary>
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index f77455485..16fd1d42b 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.IO;
@@ -11,11 +12,11 @@ namespace MediaBrowser.Controller.Providers
{
private readonly IFileSystem _fileSystem;
- private readonly Dictionary<string, FileSystemMetadata[]> _cache = new Dictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new ConcurrentDictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
- private readonly Dictionary<string, FileSystemMetadata> _fileCache = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
- private readonly Dictionary<string, List<string>> _filePathCache = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new ConcurrentDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
public DirectoryService(IFileSystem fileSystem)
{
@@ -24,14 +25,7 @@ namespace MediaBrowser.Controller.Providers
public FileSystemMetadata[] GetFileSystemEntries(string path)
{
- if (!_cache.TryGetValue(path, out FileSystemMetadata[] entries))
- {
- entries = _fileSystem.GetFileSystemEntries(path).ToArray();
-
- _cache[path] = entries;
- }
-
- return entries;
+ return _cache.GetOrAdd(path, p => _fileSystem.GetFileSystemEntries(p).ToArray());
}
public List<FileSystemMetadata> GetFiles(string path)
@@ -51,21 +45,19 @@ namespace MediaBrowser.Controller.Providers
public FileSystemMetadata GetFile(string path)
{
- if (!_fileCache.TryGetValue(path, out FileSystemMetadata file))
+ var result = _fileCache.GetOrAdd(path, p =>
{
- file = _fileSystem.GetFileInfo(path);
+ var file = _fileSystem.GetFileInfo(p);
+ return file != null && file.Exists ? file : null;
+ });
- if (file != null && file.Exists)
- {
- _fileCache[path] = file;
- }
- else
- {
- return null;
- }
+ if (result == null)
+ {
+ // lets not store null results in the cache
+ _fileCache.TryRemove(path, out _);
}
- return file;
+ return result;
}
public IReadOnlyList<string> GetFilePaths(string path)
@@ -73,14 +65,12 @@ namespace MediaBrowser.Controller.Providers
public IReadOnlyList<string> GetFilePaths(string path, bool clearCache)
{
- if (clearCache || !_filePathCache.TryGetValue(path, out List<string> result))
+ if (clearCache)
{
- result = _fileSystem.GetFilePaths(path).ToList();
-
- _filePathCache[path] = result;
+ _filePathCache.TryRemove(path, out _);
}
- return result;
+ return _filePathCache.GetOrAdd(path, p => _fileSystem.GetFilePaths(p).ToList());
}
}
}
diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
index 49974c2a3..b777cc1d3 100644
--- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
@@ -15,6 +15,12 @@ namespace MediaBrowser.Controller.Providers
public string Name { get; set; }
/// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+
+ /// <summary>
/// Gets or sets the metadata language.
/// </summary>
/// <value>The metadata language.</value>
diff --git a/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
new file mode 100644
index 000000000..959a2d771
--- /dev/null
+++ b/MediaBrowser.Controller/QuickConnect/IQuickConnect.cs
@@ -0,0 +1,87 @@
+using System;
+using MediaBrowser.Model.QuickConnect;
+
+namespace MediaBrowser.Controller.QuickConnect
+{
+ /// <summary>
+ /// Quick connect standard interface.
+ /// </summary>
+ public interface IQuickConnect
+ {
+ /// <summary>
+ /// Gets or sets the length of user facing codes.
+ /// </summary>
+ int CodeLength { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of internal access tokens.
+ /// </summary>
+ string TokenName { get; set; }
+
+ /// <summary>
+ /// Gets the current state of quick connect.
+ /// </summary>
+ QuickConnectState State { get; }
+
+ /// <summary>
+ /// Gets or sets the time (in minutes) before quick connect will automatically deactivate.
+ /// </summary>
+ int Timeout { get; set; }
+
+ /// <summary>
+ /// Assert that quick connect is currently active and throws an exception if it is not.
+ /// </summary>
+ void AssertActive();
+
+ /// <summary>
+ /// Temporarily activates quick connect for a short amount of time.
+ /// </summary>
+ void Activate();
+
+ /// <summary>
+ /// Changes the state of quick connect.
+ /// </summary>
+ /// <param name="newState">New state to change to.</param>
+ void SetState(QuickConnectState newState);
+
+ /// <summary>
+ /// Initiates a new quick connect request.
+ /// </summary>
+ /// <returns>A quick connect result with tokens to proceed or throws an exception if not active.</returns>
+ QuickConnectResult TryConnect();
+
+ /// <summary>
+ /// Checks the status of an individual request.
+ /// </summary>
+ /// <param name="secret">Unique secret identifier of the request.</param>
+ /// <returns>Quick connect result.</returns>
+ QuickConnectResult CheckRequestStatus(string secret);
+
+ /// <summary>
+ /// Authorizes a quick connect request to connect as the calling user.
+ /// </summary>
+ /// <param name="userId">User id.</param>
+ /// <param name="code">Identifying code for the request.</param>
+ /// <returns>A boolean indicating if the authorization completed successfully.</returns>
+ bool AuthorizeRequest(Guid userId, string code);
+
+ /// <summary>
+ /// Expire quick connect requests that are over the time limit. If <paramref name="expireAll"/> is true, all requests are unconditionally expired.
+ /// </summary>
+ /// <param name="expireAll">If true, all requests will be expired.</param>
+ void ExpireRequests(bool expireAll = false);
+
+ /// <summary>
+ /// Deletes all quick connect access tokens for the provided user.
+ /// </summary>
+ /// <param name="user">Guid of the user to delete tokens for.</param>
+ /// <returns>A count of the deleted tokens.</returns>
+ int DeleteAllDevices(Guid user);
+
+ /// <summary>
+ /// Generates a short code to display to the user to uniquely identify this request.
+ /// </summary>
+ /// <returns>A short, unique alphanumeric string.</returns>
+ string GenerateCode();
+ }
+}
diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs
index b99c46843..eb7fb793a 100644
--- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs
+++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs
@@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Resolvers
/// <param name="args">The args.</param>
/// <returns>BaseItem.</returns>
BaseItem ResolvePath(ItemResolveArgs args);
+
/// <summary>
/// Gets the priority.
/// </summary>
diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs
index 22d6e2a04..bc4ccd44c 100644
--- a/MediaBrowser.Controller/Session/ISessionController.cs
+++ b/MediaBrowser.Controller/Session/ISessionController.cs
@@ -3,6 +3,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Session;
namespace MediaBrowser.Controller.Session
{
@@ -23,6 +24,6 @@ namespace MediaBrowser.Controller.Session
/// <summary>
/// Sends the message.
/// </summary>
- Task SendMessage<T>(string name, Guid messageId, T data, CancellationToken cancellationToken);
+ Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 9237d21df..04c3004ee 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -188,16 +188,16 @@ namespace MediaBrowser.Controller.Session
/// <param name="data">The data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken);
+ Task SendMessageToAdminSessions<T>(SessionMessageType name, T data, CancellationToken cancellationToken);
/// <summary>
/// Sends the message to user sessions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>Task.</returns>
- Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken);
+ Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, T data, CancellationToken cancellationToken);
- Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken);
+ Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, Func<T> dataFn, CancellationToken cancellationToken);
/// <summary>
/// Sends the message to user device sessions.
@@ -208,7 +208,7 @@ namespace MediaBrowser.Controller.Session
/// <param name="data">The data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken);
+ Task SendMessageToUserDeviceSessions<T>(string deviceId, SessionMessageType name, T data, CancellationToken cancellationToken);
/// <summary>
/// Sends the restart required message.
@@ -267,6 +267,14 @@ namespace MediaBrowser.Controller.Session
Task<AuthenticationResult> AuthenticateNewSession(AuthenticationRequest request);
/// <summary>
+ /// Authenticates a new session with quick connect.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="token">Quick connect access token.</param>
+ /// <returns>Task{SessionInfo}.</returns>
+ Task<AuthenticationResult> AuthenticateQuickConnect(AuthenticationRequest request, string token);
+
+ /// <summary>
/// Creates the new session.
/// </summary>
/// <param name="request">The request.</param>
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 054fd33d9..ce58a60b9 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -22,7 +22,6 @@ namespace MediaBrowser.Controller.Session
private readonly ISessionManager _sessionManager;
private readonly ILogger _logger;
-
private readonly object _progressLock = new object();
private Timer _progressTimer;
private PlaybackProgressInfo _lastProgressInfo;
@@ -231,8 +230,8 @@ namespace MediaBrowser.Controller.Session
/// Gets or sets the supported commands.
/// </summary>
/// <value>The supported commands.</value>
- public string[] SupportedCommands
- => Capabilities == null ? Array.Empty<string>() : Capabilities.SupportedCommands;
+ public GeneralCommandType[] SupportedCommands
+ => Capabilities == null ? Array.Empty<GeneralCommandType>() : Capabilities.SupportedCommands;
public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory)
{
diff --git a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs
index e742df517..a1cada25c 100644
--- a/MediaBrowser.Controller/SyncPlay/GroupInfo.cs
+++ b/MediaBrowser.Controller/SyncPlay/GroupInfo.cs
@@ -14,12 +14,12 @@ namespace MediaBrowser.Controller.SyncPlay
public class GroupInfo
{
/// <summary>
- /// Gets the default ping value used for sessions.
+ /// The default ping value used for sessions.
/// </summary>
- public long DefaultPing { get; } = 500;
+ public const long DefaultPing = 500;
/// <summary>
- /// Gets or sets the group identifier.
+ /// Gets the group identifier.
/// </summary>
/// <value>The group identifier.</value>
public Guid GroupId { get; } = Guid.NewGuid();
@@ -58,7 +58,8 @@ namespace MediaBrowser.Controller.SyncPlay
/// <summary>
/// Checks if a session is in this group.
/// </summary>
- /// <value><c>true</c> if the session is in this group; <c>false</c> otherwise.</value>
+ /// <param name="sessionId">The session id to check.</param>
+ /// <returns><c>true</c> if the session is in this group; <c>false</c> otherwise.</returns>
public bool ContainsSession(string sessionId)
{
return Participants.ContainsKey(sessionId);
@@ -70,16 +71,14 @@ namespace MediaBrowser.Controller.SyncPlay
/// <param name="session">The session.</param>
public void AddSession(SessionInfo session)
{
- if (ContainsSession(session.Id))
- {
- return;
- }
-
- var member = new GroupMember();
- member.Session = session;
- member.Ping = DefaultPing;
- member.IsBuffering = false;
- Participants[session.Id] = member;
+ Participants.TryAdd(
+ session.Id,
+ new GroupMember
+ {
+ Session = session,
+ Ping = DefaultPing,
+ IsBuffering = false
+ });
}
/// <summary>
@@ -88,12 +87,7 @@ namespace MediaBrowser.Controller.SyncPlay
/// <param name="session">The session.</param>
public void RemoveSession(SessionInfo session)
{
- if (!ContainsSession(session.Id))
- {
- return;
- }
-
- Participants.Remove(session.Id, out _);
+ Participants.Remove(session.Id);
}
/// <summary>
@@ -103,18 +97,16 @@ namespace MediaBrowser.Controller.SyncPlay
/// <param name="ping">The ping.</param>
public void UpdatePing(SessionInfo session, long ping)
{
- if (!ContainsSession(session.Id))
+ if (Participants.TryGetValue(session.Id, out GroupMember value))
{
- return;
+ value.Ping = ping;
}
-
- Participants[session.Id].Ping = ping;
}
/// <summary>
/// Gets the highest ping in the group.
/// </summary>
- /// <value name="session">The highest ping in the group.</value>
+ /// <returns>The highest ping in the group.</returns>
public long GetHighestPing()
{
long max = long.MinValue;
@@ -133,18 +125,16 @@ namespace MediaBrowser.Controller.SyncPlay
/// <param name="isBuffering">The state.</param>
public void SetBuffering(SessionInfo session, bool isBuffering)
{
- if (!ContainsSession(session.Id))
+ if (Participants.TryGetValue(session.Id, out GroupMember value))
{
- return;
+ value.IsBuffering = isBuffering;
}
-
- Participants[session.Id].IsBuffering = isBuffering;
}
/// <summary>
/// Gets the group buffering state.
/// </summary>
- /// <value><c>true</c> if there is a session buffering in the group; <c>false</c> otherwise.</value>
+ /// <returns><c>true</c> if there is a session buffering in the group; <c>false</c> otherwise.</returns>
public bool IsBuffering()
{
foreach (var session in Participants.Values)
@@ -161,7 +151,7 @@ namespace MediaBrowser.Controller.SyncPlay
/// <summary>
/// Checks if the group is empty.
/// </summary>
- /// <value><c>true</c> if the group is empty; <c>false</c> otherwise.</value>
+ /// <returns><c>true</c> if the group is empty; <c>false</c> otherwise.</returns>
public bool IsEmpty()
{
return Participants.Count == 0;