diff options
Diffstat (limited to 'MediaBrowser.Controller')
22 files changed, 186 insertions, 264 deletions
diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index a6ee7c505..41a7686a3 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Dlna; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Dlna { @@ -17,7 +18,7 @@ namespace MediaBrowser.Controller.Dlna /// </summary> /// <param name="headers">The headers.</param> /// <returns>DeviceProfile.</returns> - DeviceProfile GetProfile(IDictionary<string, string> headers); + DeviceProfile GetProfile(IHeaderDictionary headers); /// <summary> /// Gets the default profile. @@ -64,7 +65,7 @@ namespace MediaBrowser.Controller.Dlna /// <param name="serverUuId">The server uu identifier.</param> /// <param name="serverAddress">The server address.</param> /// <returns>System.String.</returns> - string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress); + string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress); /// <summary> /// Gets the icon. diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index aa99f6b58..cdaf95f5c 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -36,9 +36,7 @@ namespace MediaBrowser.Controller.Dto .ToArray(); public bool ContainsField(ItemFields field) - { - return AllItemFields.Contains(field); - } + => Fields.Contains(field); public DtoOptions(bool allFields) { @@ -47,15 +45,7 @@ namespace MediaBrowser.Controller.Dto EnableUserData = true; AddCurrentProgram = true; - if (allFields) - { - Fields = AllItemFields; - } - else - { - Fields = new ItemFields[] { }; - } - + Fields = allFields ? AllItemFields : Array.Empty<ItemFields>(); ImageTypes = AllImageTypes; } diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index df5ec5dd0..4b6fd58fe 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -57,9 +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(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null); - - BaseItemDto[] GetBaseItemDtos(List<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null); + 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/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 72c4e3573..e20641c99 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -36,10 +36,26 @@ namespace MediaBrowser.Controller.Entities /// </summary> public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo> { - protected static MetadataFields[] EmptyMetadataFieldsArray = Array.Empty<MetadataFields>(); - protected static MediaUrl[] EmptyMediaUrlArray = Array.Empty<MediaUrl>(); - protected static ItemImageInfo[] EmptyItemImageInfoArray = Array.Empty<ItemImageInfo>(); - public static readonly LinkedChild[] EmptyLinkedChildArray = Array.Empty<LinkedChild>(); + /// <summary> + /// The supported image extensions + /// </summary> + public static readonly string[] SupportedImageExtensions + = new [] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; + + private static readonly List<string> _supportedExtensions = new List<string>(SupportedImageExtensions) + { + ".nfo", + ".xml", + ".srt", + ".vtt", + ".sub", + ".idx", + ".txt", + ".edl", + ".bif", + ".smi", + ".ttml" + }; protected BaseItem() { @@ -49,8 +65,8 @@ namespace MediaBrowser.Controller.Entities Genres = Array.Empty<string>(); Studios = Array.Empty<string>(); ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - LockedFields = EmptyMetadataFieldsArray; - ImageInfos = EmptyItemImageInfoArray; + LockedFields = Array.Empty<MetadataFields>(); + ImageInfos = Array.Empty<ItemImageInfo>(); ProductionLocations = Array.Empty<string>(); RemoteTrailers = Array.Empty<MediaUrl>(); ExtraIds = Array.Empty<Guid>(); @@ -60,11 +76,6 @@ namespace MediaBrowser.Controller.Entities public static char SlugChar = '-'; /// <summary> - /// The supported image extensions - /// </summary> - public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; - - /// <summary> /// The trailer folder name /// </summary> public static string TrailerFolderName = "trailers"; @@ -1283,6 +1294,35 @@ namespace MediaBrowser.Controller.Entities }).OrderBy(i => i.Path).ToArray(); } + protected virtual BaseItem[] LoadExtras(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService) + { + var files = fileSystemChildren.Where(i => i.IsDirectory) + .SelectMany(i => FileSystem.GetFiles(i.FullName)); + + return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions()) + .OfType<Video>() + .Select(item => + { + // Try to retrieve it from the db. If we don't find it, use the resolved version + var dbItem = LibraryManager.GetItemById(item.Id) as Video; + + if (dbItem != null) + { + item = dbItem; + } + else + { + // item is new + item.ExtraType = MediaBrowser.Model.Entities.ExtraType.Clip; + } + + return item; + + // Sort them so that the list can be easily compared for changes + }).OrderBy(i => i.Path).ToArray(); + } + + public Task RefreshMetadata(CancellationToken cancellationToken) { return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken); @@ -1371,6 +1411,8 @@ namespace MediaBrowser.Controller.Entities var themeVideosChanged = false; + var extrasChanged = false; + var localTrailersChanged = false; if (IsFileProtocol && SupportsOwnedItems) @@ -1382,6 +1424,8 @@ namespace MediaBrowser.Controller.Entities themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); themeVideosChanged = await RefreshThemeVideos(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + + extrasChanged = await RefreshExtras(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false); } } @@ -1392,7 +1436,7 @@ namespace MediaBrowser.Controller.Entities } } - return themeSongsChanged || themeVideosChanged || localTrailersChanged; + return themeSongsChanged || themeVideosChanged || extrasChanged || localTrailersChanged; } protected virtual FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService) @@ -1435,6 +1479,31 @@ namespace MediaBrowser.Controller.Entities return itemsChanged; } + private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) + { + var newExtras = LoadExtras(fileSystemChildren, options.DirectoryService).Concat(LoadThemeVideos(fileSystemChildren, options.DirectoryService)).Concat(LoadThemeSongs(fileSystemChildren, options.DirectoryService)); + + var newExtraIds = newExtras.Select(i => i.Id).ToArray(); + + var extrasChanged = !item.ExtraIds.SequenceEqual(newExtraIds); + + if (extrasChanged) + { + var ownerId = item.Id; + + var tasks = newExtras.Select(i => + { + return RefreshMetadataForOwnedItem(i, true, new MetadataRefreshOptions(options), cancellationToken); + }); + + await Task.WhenAll(tasks).ConfigureAwait(false); + + item.ExtraIds = newExtraIds; + } + + return extrasChanged; + } + private async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken) { var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService); @@ -2394,10 +2463,8 @@ namespace MediaBrowser.Controller.Entities } var filename = System.IO.Path.GetFileNameWithoutExtension(Path); - var extensions = new List<string> { ".nfo", ".xml", ".srt", ".vtt", ".sub", ".idx", ".txt", ".edl", ".bif", ".smi", ".ttml" }; - extensions.AddRange(SupportedImageExtensions); - return FileSystem.GetFiles(System.IO.Path.GetDirectoryName(Path), extensions.ToArray(), false, false) + return FileSystem.GetFiles(System.IO.Path.GetDirectoryName(Path), _supportedExtensions, false, false) .Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase)) .ToList(); } @@ -2775,17 +2842,17 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetExtras() { - return ThemeVideoIds.Select(LibraryManager.GetItemById).Where(i => i.ExtraType.Equals(Model.Entities.ExtraType.ThemeVideo)).OrderBy(i => i.SortName); + return ExtraIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName); } - public IEnumerable<BaseItem> GetExtras(ExtraType[] unused) + public IEnumerable<BaseItem> GetExtras(ExtraType[] extraTypes) { - return GetExtras(); + return ExtraIds.Select(LibraryManager.GetItemById).Where(i => i != null && extraTypes.Contains(i.ExtraType.Value)).OrderBy(i => i.SortName); } public IEnumerable<BaseItem> GetDisplayExtras() { - return GetExtras(); + return GetExtras(DisplayExtraTypes); } public virtual bool IsHD => Height >= 720; @@ -2798,8 +2865,10 @@ namespace MediaBrowser.Controller.Entities { return RunTimeTicks ?? 0; } - // what does this do? - public static ExtraType[] DisplayExtraTypes = new[] { Model.Entities.ExtraType.ThemeSong, Model.Entities.ExtraType.ThemeVideo }; + + // 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 virtual bool SupportsExternalTransfer => false; } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 8bfadbee6..c056bc0b4 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Controller.Entities public Folder() { - LinkedChildren = EmptyLinkedChildArray; + LinkedChildren = Array.Empty<LinkedChild>(); } [IgnoreDataMember] @@ -810,37 +810,19 @@ namespace MediaBrowser.Controller.Entities { if (query.ItemIds.Length > 0) { - var result = LibraryManager.GetItemsResult(query); - - if (query.OrderBy.Length == 0) - { - var ids = query.ItemIds.ToList(); - - // Try to preserve order - result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id)).ToArray(); - } - return result; + return LibraryManager.GetItemsResult(query); } return GetItemsInternal(query); } - public BaseItem[] GetItemList(InternalItemsQuery query) + public IReadOnlyList<BaseItem> GetItemList(InternalItemsQuery query) { query.EnableTotalRecordCount = false; if (query.ItemIds.Length > 0) { - var result = LibraryManager.GetItemList(query); - - if (query.OrderBy.Length == 0) - { - var ids = query.ItemIds.ToList(); - - // Try to preserve order - return result.OrderBy(i => ids.IndexOf(i.Id)).ToArray(); - } - return result.ToArray(); + return LibraryManager.GetItemList(query); } return GetItemsInternal(query).Items; diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs index ff6b13398..848493864 100644 --- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -25,22 +25,10 @@ namespace MediaBrowser.Controller.Entities public DateTime DateModified { get; set; } public int Width { get; set; } + public int Height { get; set; } [IgnoreDataMember] - public bool IsLocalFile - { - get - { - if (Path != null) - { - if (Path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - } - return true; - } - } + public bool IsLocalFile => Path == null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase); } } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 124a943ef..a532b5ee9 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities.Movies { public BoxSet() { - RemoteTrailers = EmptyMediaUrlArray; + RemoteTrailers = Array.Empty<MediaUrl>(); LocalTrailerIds = Array.Empty<Guid>(); RemoteTrailerIds = Array.Empty<Guid>(); diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 232d11624..20c5b3521 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -21,10 +21,10 @@ namespace MediaBrowser.Controller.Entities.Movies public Movie() { - SpecialFeatureIds = new Guid[] { }; - RemoteTrailers = EmptyMediaUrlArray; - LocalTrailerIds = new Guid[] { }; - RemoteTrailerIds = new Guid[] { }; + SpecialFeatureIds = Array.Empty<Guid>(); + RemoteTrailers = Array.Empty<MediaUrl>(); + LocalTrailerIds = Array.Empty<Guid>(); + RemoteTrailerIds = Array.Empty<Guid>(); } public Guid[] LocalTrailerIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 072b1d89a..fb29c07b0 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Entities.TV { public Episode() { - RemoteTrailers = EmptyMediaUrlArray; + RemoteTrailers = Array.Empty<MediaUrl>(); LocalTrailerIds = Array.Empty<Guid>(); RemoteTrailerIds = Array.Empty<Guid>(); } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 570e9389e..eae834f6f 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -7,7 +7,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; @@ -22,7 +21,7 @@ namespace MediaBrowser.Controller.Entities.TV { public Series() { - RemoteTrailers = EmptyMediaUrlArray; + RemoteTrailers = Array.Empty<MediaUrl>(); LocalTrailerIds = Array.Empty<Guid>(); RemoteTrailerIds = Array.Empty<Guid>(); AirDays = Array.Empty<DayOfWeek>(); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 31cd42975..8379dcc09 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -167,7 +167,7 @@ namespace MediaBrowser.Controller.Entities AdditionalParts = Array.Empty<string>(); LocalAlternateVersions = Array.Empty<string>(); SubtitleFiles = Array.Empty<string>(); - LinkedAlternateVersions = EmptyLinkedChildArray; + LinkedAlternateVersions = Array.Empty<LinkedChild>(); } public override bool CanDownload() diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 60c183d04..511356aa4 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -193,7 +193,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Updates the item. /// </summary> - void UpdateItems(List<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); + void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> @@ -520,12 +520,12 @@ namespace MediaBrowser.Controller.Library void UpdateMediaPath(string virtualFolderName, MediaPathInfo path); void RemoveMediaPath(string virtualFolderName, string path); - QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query); int GetCount(InternalItemsQuery query); diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index 5b66e7497..fd5fb6748 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -8,16 +8,6 @@ namespace MediaBrowser.Controller.Library public static class TVUtils { /// <summary> - /// The TVDB API key - /// </summary> - public static readonly string TvdbApiKey = "72930AE1CB7E2DB3"; - public static readonly string TvdbBaseUrl = "https://www.thetvdb.com/"; - /// <summary> - /// The banner URL - /// </summary> - public static readonly string BannerUrl = TvdbBaseUrl + "banners/"; - - /// <summary> /// Gets the air days. /// </summary> /// <param name="day">The day.</param> @@ -28,24 +18,24 @@ namespace MediaBrowser.Controller.Library { if (string.Equals(day, "Daily", StringComparison.OrdinalIgnoreCase)) { - return new DayOfWeek[] - { - DayOfWeek.Sunday, - DayOfWeek.Monday, - DayOfWeek.Tuesday, - DayOfWeek.Wednesday, - DayOfWeek.Thursday, - DayOfWeek.Friday, - DayOfWeek.Saturday - }; + return new[] + { + DayOfWeek.Sunday, + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday, + DayOfWeek.Saturday + }; } if (Enum.TryParse(day, true, out DayOfWeek value)) { - return new DayOfWeek[] - { - value - }; + return new[] + { + value + }; } return new DayOfWeek[] { }; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f5f147db1..e378c2b89 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1904,7 +1904,7 @@ namespace MediaBrowser.Controller.MediaEncoding { flags.Add("+ignidx"); } - if (state.GenPtsInput) + if (state.GenPtsInput || string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { flags.Add("+genpts"); } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 057e43910..d032a849e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.System; namespace MediaBrowser.Controller.MediaEncoding { @@ -14,7 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// </summary> public interface IMediaEncoder : ITranscoderSupport { - string EncoderLocationType { get; } + FFmpegLocation EncoderLocation { get; } /// <summary> /// Gets the encoder path. @@ -73,7 +74,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// <param name="inputFiles">The input files.</param> /// <param name="protocol">The protocol.</param> /// <returns>System.String.</returns> - string GetInputArgument(string[] inputFiles, MediaProtocol protocol); + string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol); /// <summary> /// Gets the time parameter. @@ -91,7 +92,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// <returns>System.String.</returns> string EscapeSubtitleFilterPath(string path); - void Init(); + void SetFFmpegPath(); void UpdateEncoderPath(string path, string pathType); bool SupportsEncoder(string encoder); diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index b812a8ddc..46593fb2f 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -32,16 +32,17 @@ namespace MediaBrowser.Controller.MediaEncoding var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line); + // If ffmpeg process is closed, the state is disposed, so don't write to target in that case + if (!target.CanWrite) + { + break; + } + await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); await target.FlushAsync().ConfigureAwait(false); } } } - catch (ObjectDisposedException) - { - //TODO Investigate and properly fix. - // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux - } catch (Exception ex) { _logger.LogError(ex, "Error reading ffmpeg log"); diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 4242a00e2..844412546 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -22,8 +22,8 @@ namespace MediaBrowser.Controller.Net /// <summary> /// The _active connections /// </summary> - protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>> ActiveConnections = - new List<Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>>(); + protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> ActiveConnections = + new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>(); /// <summary> /// Gets the name. @@ -34,9 +34,8 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Gets the data to send. /// </summary> - /// <param name="state">The state.</param> /// <returns>Task{`1}.</returns> - protected abstract Task<TReturnDataType> GetDataToSend(TStateType state, CancellationToken cancellationToken); + protected abstract Task<TReturnDataType> GetDataToSend(); /// <summary> /// The logger @@ -80,13 +79,6 @@ namespace MediaBrowser.Controller.Net protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - protected virtual bool SendOnTimer => false; - - protected virtual void ParseMessageParams(string[] values) - { - - } - /// <summary> /// Starts sending messages over a web socket /// </summary> @@ -98,19 +90,10 @@ namespace MediaBrowser.Controller.Net var dueTimeMs = long.Parse(vals[0], UsCulture); var periodMs = long.Parse(vals[1], UsCulture); - if (vals.Length > 2) - { - ParseMessageParams(vals.Skip(2).ToArray()); - } - var cancellationTokenSource = new CancellationTokenSource(); Logger.LogDebug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); - var timer = SendOnTimer ? - new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : - null; - var state = new TStateType { IntervalMs = periodMs, @@ -119,47 +102,13 @@ namespace MediaBrowser.Controller.Net lock (ActiveConnections) { - ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>(message.Connection, cancellationTokenSource, timer, state)); - } - - if (timer != null) - { - timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); + ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>(message.Connection, cancellationTokenSource, state)); } } - /// <summary> - /// Timers the callback. - /// </summary> - /// <param name="state">The state.</param> - private void TimerCallback(object state) - { - var connection = (IWebSocketConnection)state; - - Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> tuple; - - lock (ActiveConnections) - { - tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); - } - - if (tuple == null) - { - return; - } - - if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) - { - DisposeConnection(tuple); - return; - } - - SendData(tuple); - } - protected void SendData(bool force) { - Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType>[] tuples; + Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>[] tuples; lock (ActiveConnections) { @@ -168,7 +117,7 @@ namespace MediaBrowser.Controller.Net { if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) { - var state = c.Item4; + var state = c.Item3; if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) { @@ -187,17 +136,17 @@ namespace MediaBrowser.Controller.Net } } - private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> tuple) + private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, TStateType> tuple) { var connection = tuple.Item1; try { - var state = tuple.Item4; + var state = tuple.Item3; var cancellationToken = tuple.Item2.Token; - var data = await GetDataToSend(state, cancellationToken).ConfigureAwait(false); + var data = await GetDataToSend().ConfigureAwait(false); if (data != null) { @@ -246,23 +195,12 @@ namespace MediaBrowser.Controller.Net /// Disposes the connection. /// </summary> /// <param name="connection">The connection.</param> - private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, Timer, TStateType> connection) + private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, TStateType> connection) { Logger.LogDebug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); - var timer = connection.Item3; - - if (timer != null) - { - try - { - timer.Dispose(); - } - catch (ObjectDisposedException) - { - //TODO Investigate and properly fix. - } - } + // TODO disposing the connection seems to break websockets in subtle ways, so what is the purpose of this function really... + // connection.Item1.Dispose(); try { diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index f41303007..46933c046 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Model.Events; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { @@ -29,11 +32,30 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Inits this instance. /// </summary> - void Init(IEnumerable<IService> services, IEnumerable<IWebSocketListener> listener); + void Init(IEnumerable<IService> services, IEnumerable<IWebSocketListener> listener, IEnumerable<string> urlPrefixes); /// <summary> /// If set, all requests will respond with this message /// </summary> string GlobalResponse { get; set; } + + /// <summary> + /// Sends the http context to the socket listener + /// </summary> + /// <param name="ctx"></param> + /// <returns></returns> + Task ProcessWebSocketRequest(HttpContext ctx); + + /// <summary> + /// The HTTP request handler + /// </summary> + /// <param name="httpReq"></param> + /// <param name="urlString"></param> + /// <param name="host"></param> + /// <param name="localPath"></param> + /// <param name="cancellationToken"></param> + /// <returns></returns> + Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, + CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index a09b2f7a2..566897b31 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; using MediaBrowser.Model.Services; +using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net { @@ -35,7 +36,7 @@ namespace MediaBrowser.Controller.Net /// Gets or sets the query string. /// </summary> /// <value>The query string.</value> - QueryParamCollection QueryString { get; set; } + IQueryCollection QueryString { get; set; } /// <summary> /// Gets or sets the receive action. diff --git a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs deleted file mode 100644 index f26b764bb..000000000 --- a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Controller.Net -{ - /// <summary> - /// Class WebSocketConnectEventArgs - /// </summary> - public class WebSocketConnectingEventArgs : EventArgs - { - /// <summary> - /// Gets or sets the URL. - /// </summary> - /// <value>The URL.</value> - public string Url { get; set; } - /// <summary> - /// Gets or sets the endpoint. - /// </summary> - /// <value>The endpoint.</value> - public string Endpoint { get; set; } - /// <summary> - /// Gets or sets the query string. - /// </summary> - /// <value>The query string.</value> - public QueryParamCollection QueryString { get; set; } - /// <summary> - /// Gets or sets a value indicating whether [allow connection]. - /// </summary> - /// <value><c>true</c> if [allow connection]; otherwise, <c>false</c>.</value> - public bool AllowConnection { get; set; } - - public WebSocketConnectingEventArgs() - { - QueryString = new QueryParamCollection(); - AllowConnection = true; - } - } - -} diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 5156fce11..47e0f3453 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Persistence /// </summary> /// <param name="items">The items.</param> /// <param name="cancellationToken">The cancellation token.</param> - void SaveItems(List<BaseItem> items, CancellationToken cancellationToken); + void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken); void SaveImages(BaseItem item); @@ -141,12 +141,12 @@ namespace MediaBrowser.Controller.Persistence int GetCount(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query); + QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query); List<string> GetMusicGenreNames(); List<string> GetStudioNames(); diff --git a/MediaBrowser.Controller/Security/IEncryptionManager.cs b/MediaBrowser.Controller/Security/IEncryptionManager.cs deleted file mode 100644 index 68680fdf3..000000000 --- a/MediaBrowser.Controller/Security/IEncryptionManager.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace MediaBrowser.Controller.Security -{ - public interface IEncryptionManager - { - /// <summary> - /// Encrypts the string. - /// </summary> - /// <param name="value">The value.</param> - /// <returns>System.String.</returns> - string EncryptString(string value); - - /// <summary> - /// Decrypts the string. - /// </summary> - /// <param name="value">The value.</param> - /// <returns>System.String.</returns> - string DecryptString(string value); - } -} |
