From 6c9274730bd2c024e96abfa32b97e0bd5ccda8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BCnktchen?= Date: Fri, 28 Jul 2017 18:15:31 +0200 Subject: [PATCH 01/73] Improve playback of RTSP streams Without those little changes, rtsp live tv streams get corrupted even when stream copying, but also with transcoding. It's already really bad for sd streams, but hd streams are just unwatchable. The whole picture consists of green blocks. Btw. this problem isn't new. It was already discussed in many posts at the time the Argus TV plugin was still alive. These changes have the potential to fix it there also. --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 42f0dda160..bd7bbb6fe2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1551,6 +1551,11 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier += " " + GetFastSeekCommandLineParameter(state.BaseRequest); inputModifier = inputModifier.Trim(); + + if (state.InputProtocol == MediaProtocol.Rtsp) + { + inputModifier += " -rtsp_transport tcp"; + } if (!string.IsNullOrEmpty(state.InputAudioSync)) { @@ -1562,7 +1567,7 @@ namespace MediaBrowser.Controller.MediaEncoding inputModifier += " -vsync " + state.InputVideoSync; } - if (state.ReadInputAtNativeFramerate) + if (state.ReadInputAtNativeFramerate && state.InputProtocol != MediaProtocol.Rtsp) { inputModifier += " -re"; } From ed8159117519209418d04e293e116ad4b6711492 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 27 Aug 2017 20:33:05 -0400 Subject: [PATCH 02/73] update dto methods --- Emby.Dlna/PlayTo/PlayToController.cs | 3 +++ .../Channels/ChannelManager.cs | 11 ++++----- Emby.Server.Implementations/Dto/DtoService.cs | 14 +++++------ .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/LiveTvManager.cs | 18 ++++++-------- MediaBrowser.Api/GamesService.cs | 10 ++++---- MediaBrowser.Api/LiveTv/LiveTvService.cs | 9 ++++--- MediaBrowser.Api/Movies/MoviesService.cs | 18 +++++++------- MediaBrowser.Api/Music/AlbumsService.cs | 17 +++++++------ MediaBrowser.Api/Music/InstantMixService.cs | 21 ++++++++-------- MediaBrowser.Api/PlaylistService.cs | 5 ++-- MediaBrowser.Api/SimilarItemsHelper.cs | 4 ++-- MediaBrowser.Api/SuggestionsService.cs | 8 +++---- MediaBrowser.Api/TvShowsService.cs | 24 +++++++++---------- MediaBrowser.Api/UserLibrary/ItemsService.cs | 9 ++++--- MediaBrowser.Controller/Dto/IDtoService.cs | 7 ++---- .../LiveTv/ILiveTvManager.cs | 4 ++-- SharedVersion.cs | 2 +- 18 files changed, 87 insertions(+), 99 deletions(-) diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 4b77f998d3..f1b18a5433 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -386,6 +386,9 @@ namespace Emby.Dlna.PlayTo case PlaystateCommand.Unpause: return _device.SetPlay(); + case PlaystateCommand.PlayPause: + return _device.IsPaused ? _device.SetPlay() : _device.SetPause(); + case PlaystateCommand.Seek: { return Seek(command.SeekPositionTicks ?? 0); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index fcc637b254..1a90c85eec 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -182,8 +182,7 @@ namespace Emby.Server.Implementations.Channels { }; - var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) - .ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user); var result = new QueryResult { @@ -567,7 +566,7 @@ namespace Emby.Server.Implementations.Channels Fields = query.Fields }; - var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user); var result = new QueryResult { @@ -832,8 +831,7 @@ namespace Emby.Server.Implementations.Channels Fields = query.Fields }; - var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) - .ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user); var result = new QueryResult { @@ -984,8 +982,7 @@ namespace Emby.Server.Implementations.Channels Fields = query.Fields }; - var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) - .ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user); var result = new QueryResult { diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 0282572708..22793e6529 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -87,17 +87,17 @@ namespace Emby.Server.Implementations.Dto return GetBaseItemDto(item, options, user, owner); } - public Task GetBaseItemDtos(List items, DtoOptions options, User user = null, BaseItem owner = null) + public BaseItemDto[] GetBaseItemDtos(List items, DtoOptions options, User user = null, BaseItem owner = null) { return GetBaseItemDtos(items, items.Count, options, user, owner); } - public Task GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null) + public BaseItemDto[] GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null) { return GetBaseItemDtos(items, items.Length, options, user, owner); } - public async Task GetBaseItemDtos(IEnumerable items, int itemCount, DtoOptions options, User user = null, BaseItem owner = null) + public BaseItemDto[] GetBaseItemDtos(IEnumerable items, int itemCount, DtoOptions options, User user = null, BaseItem owner = null) { if (items == null) { @@ -157,12 +157,13 @@ namespace Emby.Server.Implementations.Dto if (programTuples.Count > 0) { - await _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user).ConfigureAwait(false); + var task = _livetvManager().AddInfoToProgramDto(programTuples, options.Fields, user); + Task.WaitAll(task); } if (channelTuples.Count > 0) { - await _livetvManager().AddChannelInfo(channelTuples, options, user).ConfigureAwait(false); + _livetvManager().AddChannelInfo(channelTuples, options, user); } return returnItems; @@ -177,8 +178,7 @@ namespace Emby.Server.Implementations.Dto if (tvChannel != null) { var list = new List> { new Tuple(dto, tvChannel) }; - var task = _livetvManager().AddChannelInfo(list, options, user); - Task.WaitAll(task); + _livetvManager().AddChannelInfo(list, options, user); } else if (item is LiveTvProgram) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2e12f46bf9..f1694efb40 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1810,7 +1810,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var config = GetConfiguration(); - var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false); + var regInfo = await _liveTvManager.GetRegistrationInfo("dvr").ConfigureAwait(false); if (regInfo.IsValid) { diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index ac98d1043a..185935e884 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -985,8 +985,7 @@ namespace Emby.Server.Implementations.LiveTv var queryResult = _libraryManager.QueryItems(internalQuery); - var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user); var result = new QueryResult { @@ -1070,8 +1069,7 @@ namespace Emby.Server.Implementations.LiveTv var user = _userManager.GetUserById(query.UserId); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); var result = new QueryResult { @@ -1656,7 +1654,7 @@ namespace Emby.Server.Implementations.LiveTv }); } - public async Task> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) + public QueryResult GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); if (user != null && !IsLiveTvEnabled(user)) @@ -1702,8 +1700,7 @@ namespace Emby.Server.Implementations.LiveTv DtoOptions = options }); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); return new QueryResult { @@ -2040,8 +2037,7 @@ namespace Emby.Server.Implementations.LiveTv var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); return new QueryResult { @@ -2368,7 +2364,7 @@ namespace Emby.Server.Implementations.LiveTv }; } - public async Task AddChannelInfo(List> tuples, DtoOptions options, User user) + public void AddChannelInfo(List> tuples, DtoOptions options, User user) { var now = DateTime.UtcNow; @@ -2425,7 +2421,7 @@ namespace Emby.Server.Implementations.LiveTv if (addCurrentProgram) { - var currentProgramDtos = await _dtoService.GetBaseItemDtos(currentProgramsList, options, user).ConfigureAwait(false); + var currentProgramDtos = _dtoService.GetBaseItemDtos(currentProgramsList, options, user); foreach (var programDto in currentProgramDtos) { diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 8a16cbfa16..6c48b732f6 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -128,7 +128,7 @@ namespace MediaBrowser.Api DisplayName = system.Name }; - var items = user == null ? + var items = user == null ? system.GetRecursiveChildren(i => i is Game) : system.GetRecursiveChildren(user, new InternalItemsQuery(user) { @@ -157,14 +157,14 @@ namespace MediaBrowser.Api /// /// The request. /// System.Object. - public async Task Get(GetSimilarGames request) + public object Get(GetSimilarGames request) { - var result = await GetSimilarItemsResult(request).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } - private async Task> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -186,7 +186,7 @@ namespace MediaBrowser.Api }); - var returnList = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)); + var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user); var result = new QueryResult { diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index e866be9c67..81b0894ac3 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -922,8 +922,7 @@ namespace MediaBrowser.Api.LiveTv options.AddCurrentProgram = request.AddCurrentProgram; - var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, options, user); var result = new QueryResult { @@ -1075,12 +1074,12 @@ namespace MediaBrowser.Api.LiveTv return ToOptimizedResult(result); } - public async Task Get(GetRecordingSeries request) + public object Get(GetRecordingSeries request) { var options = GetDtoOptions(_authContext, request); options.DeviceId = _authContext.GetAuthorizationInfo(Request).DeviceId; - var result = await _liveTvManager.GetRecordingSeries(new RecordingQuery + var result = _liveTvManager.GetRecordingSeries(new RecordingQuery { ChannelId = request.ChannelId, UserId = request.UserId, @@ -1092,7 +1091,7 @@ namespace MediaBrowser.Api.LiveTv IsInProgress = request.IsInProgress, EnableTotalRecordCount = request.EnableTotalRecordCount - }, options, CancellationToken.None).ConfigureAwait(false); + }, options, CancellationToken.None); return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 3e42026b14..9157e6d89c 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -113,16 +113,16 @@ namespace MediaBrowser.Api.Movies /// /// The request. /// System.Object. - public async Task Get(GetSimilarMovies request) + public object Get(GetSimilarMovies request) { - var result = await GetSimilarItemsResult(request).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } - public async Task Get(GetSimilarTrailers request) + public object Get(GetSimilarTrailers request) { - var result = await GetSimilarItemsResult(request).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } @@ -138,7 +138,7 @@ namespace MediaBrowser.Api.Movies return ToOptimizedResult(result); } - private async Task> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -166,7 +166,7 @@ namespace MediaBrowser.Api.Movies }); - var returnList = await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false); + var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user); var result = new QueryResult { @@ -313,7 +313,7 @@ namespace MediaBrowser.Api.Movies if (items.Count > 0) { - var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result; + var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user); yield return new RecommendationDto { @@ -353,7 +353,7 @@ namespace MediaBrowser.Api.Movies if (items.Count > 0) { - var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user).Result; + var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user); yield return new RecommendationDto { @@ -390,7 +390,7 @@ namespace MediaBrowser.Api.Movies if (similar.Count > 0) { - var returnItems = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).Result; + var returnItems = _dtoService.GetBaseItemDtos(similar, dtoOptions, user); yield return new RecommendationDto { diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs index bc7ae2be27..d7986fa501 100644 --- a/MediaBrowser.Api/Music/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -7,7 +7,6 @@ using MediaBrowser.Controller.Persistence; using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using MediaBrowser.Model.Services; namespace MediaBrowser.Api.Music @@ -52,43 +51,43 @@ namespace MediaBrowser.Api.Music _authContext = authContext; } - public async Task Get(GetSimilarArtists request) + public object Get(GetSimilarArtists request) { var dtoOptions = GetDtoOptions(_authContext, request); - var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, + var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, _itemRepo, _libraryManager, _userDataRepository, _dtoService, Logger, request, new[] { typeof(MusicArtist) }, - SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + SimilarItemsHelper.GetSimiliarityScore); return ToOptimizedSerializedResultUsingCache(result); } - + /// /// Gets the specified request. /// /// The request. /// System.Object. - public async Task Get(GetSimilarAlbums request) + public object Get(GetSimilarAlbums request) { var dtoOptions = GetDtoOptions(_authContext, request); - var result = await SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, + var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, _itemRepo, _libraryManager, _userDataRepository, _dtoService, Logger, request, new[] { typeof(MusicAlbum) }, - GetAlbumSimilarityScore).ConfigureAwait(false); + GetAlbumSimilarityScore); return ToOptimizedSerializedResultUsingCache(result); } - + /// /// Gets the album similarity score. /// diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index bf6b75a3ef..8a18298f1e 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.Api.Music _authContext = authContext; } - public Task Get(GetInstantMixFromItem request) + public object Get(GetInstantMixFromItem request) { var item = _libraryManager.GetItemById(request.Id); @@ -94,7 +94,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromArtistId request) + public object Get(GetInstantMixFromArtistId request) { var item = _libraryManager.GetItemById(request.Id); @@ -107,7 +107,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromMusicGenreId request) + public object Get(GetInstantMixFromMusicGenreId request) { var item = _libraryManager.GetItemById(request.Id); @@ -120,7 +120,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromSong request) + public object Get(GetInstantMixFromSong request) { var item = _libraryManager.GetItemById(request.Id); @@ -133,7 +133,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromAlbum request) + public object Get(GetInstantMixFromAlbum request) { var album = _libraryManager.GetItemById(request.Id); @@ -146,7 +146,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromPlaylist request) + public object Get(GetInstantMixFromPlaylist request) { var playlist = (Playlist)_libraryManager.GetItemById(request.Id); @@ -159,7 +159,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromMusicGenre request) + public object Get(GetInstantMixFromMusicGenre request) { var user = _userManager.GetUserById(request.UserId); @@ -170,7 +170,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - public Task Get(GetInstantMixFromArtist request) + public object Get(GetInstantMixFromArtist request) { var user = _userManager.GetUserById(request.UserId); var artist = _libraryManager.GetArtist(request.Name, new DtoOptions(false)); @@ -182,7 +182,7 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request, dtoOptions); } - private async Task GetResult(List items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions) + private object GetResult(List items, User user, BaseGetSimilarItems request, DtoOptions dtoOptions) { var list = items; @@ -196,8 +196,7 @@ namespace MediaBrowser.Api.Music list = list.Take(request.Limit.Value).ToList(); } - var returnList = (await _dtoService.GetBaseItemDtos(list, dtoOptions, user) - .ConfigureAwait(false)); + var returnList = _dtoService.GetBaseItemDtos(list, dtoOptions, user); result.Items = returnList; diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index 54c995d3d1..2266780217 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.Api Task.WaitAll(task); } - public async Task Get(GetPlaylistItems request) + public object Get(GetPlaylistItems request) { var playlist = (Playlist)_libraryManager.GetItemById(request.Id); var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -193,8 +193,7 @@ namespace MediaBrowser.Api var dtoOptions = GetDtoOptions(_authContext, request); - var dtos = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2).ToList(), dtoOptions, user) - .ConfigureAwait(false)); + var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2).ToList(), dtoOptions, user); var index = 0; foreach (var item in dtos) diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs index 48765e698a..0b5eaa4760 100644 --- a/MediaBrowser.Api/SimilarItemsHelper.cs +++ b/MediaBrowser.Api/SimilarItemsHelper.cs @@ -71,7 +71,7 @@ namespace MediaBrowser.Api /// public static class SimilarItemsHelper { - internal static async Task> GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) + internal static QueryResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Type[] includeTypes, Func, List, BaseItem, int> getSimilarityScore) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null; @@ -104,7 +104,7 @@ namespace MediaBrowser.Api returnItems = returnItems.Take(request.Limit.Value).ToList(); } - var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false); + var dtos = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user); return new QueryResult { diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 931772e6ae..616e22519c 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -47,21 +47,21 @@ namespace MediaBrowser.Api _libraryManager = libraryManager; } - public async Task Get(GetSuggestedItems request) + public object Get(GetSuggestedItems request) { - var result = await GetResultItems(request).ConfigureAwait(false); + var result = GetResultItems(request); return ToOptimizedResult(result); } - private async Task> GetResultItems(GetSuggestedItems request) + private QueryResult GetResultItems(GetSuggestedItems request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var dtoOptions = GetDtoOptions(_authContext, request); var result = GetItems(request, user, dtoOptions); - var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false); + var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user); if (dtoList == null) { diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 4b1e69c5d1..3d01166657 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -293,14 +293,14 @@ namespace MediaBrowser.Api /// /// The request. /// System.Object. - public async Task Get(GetSimilarShows request) + public object Get(GetSimilarShows request) { - var result = await GetSimilarItemsResult(request).ConfigureAwait(false); + var result = GetSimilarItemsResult(request); return ToOptimizedSerializedResultUsingCache(result); } - private async Task> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) + private QueryResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -322,7 +322,7 @@ namespace MediaBrowser.Api }); - var returnList = (await _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user).ConfigureAwait(false)); + var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user); var result = new QueryResult { @@ -334,7 +334,7 @@ namespace MediaBrowser.Api return result; } - public async Task Get(GetUpcomingEpisodes request) + public object Get(GetUpcomingEpisodes request) { var user = _userManager.GetUserById(request.UserId); @@ -358,7 +358,7 @@ namespace MediaBrowser.Api }); - var returnItems = (await _dtoService.GetBaseItemDtos(itemsResult, options, user).ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(itemsResult, options, user); var result = new QueryResult { @@ -374,7 +374,7 @@ namespace MediaBrowser.Api /// /// The request. /// System.Object. - public async Task Get(GetNextUpEpisodes request) + public object Get(GetNextUpEpisodes request) { var options = GetDtoOptions(_authContext, request); @@ -390,7 +390,7 @@ namespace MediaBrowser.Api var user = _userManager.GetUserById(request.UserId); - var returnItems = (await _dtoService.GetBaseItemDtos(result.Items, options, user).ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user); return ToOptimizedSerializedResultUsingCache(new QueryResult { @@ -423,7 +423,7 @@ namespace MediaBrowser.Api return items; } - public async Task Get(GetSeasons request) + public object Get(GetSeasons request) { var user = _userManager.GetUserById(request.UserId); @@ -444,7 +444,7 @@ namespace MediaBrowser.Api var dtoOptions = GetDtoOptions(_authContext, request); - var returnItems = (await _dtoService.GetBaseItemDtos(seasons, dtoOptions, user).ConfigureAwait(false)); + var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user); return new QueryResult { @@ -463,7 +463,7 @@ namespace MediaBrowser.Api return null; } - public async Task Get(GetEpisodes request) + public object Get(GetEpisodes request) { var user = _userManager.GetUserById(request.UserId); @@ -544,7 +544,7 @@ namespace MediaBrowser.Api returnItems = ApplyPaging(episodes, request.StartIndex, request.Limit).ToList(); } - var dtos = (await _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false)); + var dtos = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user); return new QueryResult { diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 9dd5aa5651..2f946e35a9 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -84,14 +84,14 @@ namespace MediaBrowser.Api.UserLibrary /// /// The request. /// System.Object. - public async Task Get(GetItems request) + public object Get(GetItems request) { if (request == null) { throw new ArgumentNullException("request"); } - var result = await GetItems(request).ConfigureAwait(false); + var result = GetItems(request); return ToOptimizedSerializedResultUsingCache(result); } @@ -100,8 +100,7 @@ namespace MediaBrowser.Api.UserLibrary /// Gets the items. /// /// The request. - /// Task{ItemsResult}. - private async Task> GetItems(GetItems request) + private QueryResult GetItems(GetItems request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -119,7 +118,7 @@ namespace MediaBrowser.Api.UserLibrary throw new InvalidOperationException("GetItemsToSerialize result.Items returned null"); } - var dtoList = await _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ConfigureAwait(false); + var dtoList = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user); if (dtoList == null) { diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 76ecd81803..c0217330d8 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -2,7 +2,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using System.Collections.Generic; -using System.Threading.Tasks; using MediaBrowser.Controller.Sync; namespace MediaBrowser.Controller.Dto @@ -40,7 +39,6 @@ namespace MediaBrowser.Controller.Dto /// The fields. /// The user. /// The owner. - /// Task{BaseItemDto}. BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null); /// @@ -60,10 +58,9 @@ namespace MediaBrowser.Controller.Dto /// The options. /// The user. /// The owner. - /// IEnumerable<BaseItemDto>. - Task GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null); + BaseItemDto[] GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null); - Task GetBaseItemDtos(List items, DtoOptions options, User user = null, BaseItem owner = null); + BaseItemDto[] GetBaseItemDtos(List items, DtoOptions options, User user = null, BaseItem owner = null); /// /// Gets the chapter information dto. diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 6ff630590a..42c31c6299 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// QueryResult{RecordingInfoDto}. Task> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken); - Task> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken); + QueryResult GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken); /// /// Gets the timers. @@ -360,7 +360,7 @@ namespace MediaBrowser.Controller.LiveTv /// The items. /// The options. /// The user. - Task AddChannelInfo(List> items, DtoOptions options, User user); + void AddChannelInfo(List> items, DtoOptions options, User user); /// /// Called when [recording file deleted]. diff --git a/SharedVersion.cs b/SharedVersion.cs index e8903fbb5c..f946267ea3 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.28.8")] +[assembly: AssemblyVersion("3.2.29.1")] From 780b761456bd46fc7684a72a11afa35715f48c0b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 28 Aug 2017 12:41:32 -0400 Subject: [PATCH 03/73] 3.2.29.2 --- Emby.Dlna/DlnaManager.cs | 1 - .../ApplicationHost.cs | 21 +++++++++++++++---- MediaBrowser.Common/Plugins/BasePlugin.cs | 11 +++++++--- MediaBrowser.Model/Dlna/DeviceProfile.cs | 3 --- SharedVersion.cs | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 847f636198..4ff413b9bd 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -316,7 +316,6 @@ namespace Emby.Dlna profile = ReserializeProfile(tempProfile); profile.Id = path.ToLower().GetMD5().ToString("N"); - profile.ProfileType = type; _profiles[path] = new Tuple(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile); diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 70ec37a3bc..3454451022 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1482,13 +1482,26 @@ namespace Emby.Server.Implementations var assembly = plugin.GetType().Assembly; var assemblyName = assembly.GetName(); - var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]; - var assemblyId = new Guid(attribute.Value); - var assemblyFileName = assemblyName.Name + ".dll"; var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName); - assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version, assemblyId); + assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version); + + try + { + var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true); + if (idAttributes.Length > 0) + { + var attribute = (GuidAttribute)idAttributes[0]; + var assemblyId = new Guid(attribute.Value); + + assemblyPlugin.SetId(assemblyId); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error getting plugin Id from {0}.", ex, plugin.GetType().FullName); + } } var isFirstRun = !File.Exists(plugin.ConfigurationFilePath); diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index 95e076096c..73be04ac88 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -55,11 +55,15 @@ namespace MediaBrowser.Common.Plugins get { return typeof(TConfigurationType); } } - public void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion, Guid assemblyId) + public void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion) { AssemblyFilePath = assemblyFilePath; AssemblyFileName = assemblyFileName; Version = assemblyVersion; + } + + public void SetId(Guid assemblyId) + { Id = assemblyId; } @@ -78,7 +82,7 @@ namespace MediaBrowser.Common.Plugins /// Gets the unique id. /// /// The unique id. - public Guid Id { get; private set; } + public virtual Guid Id { get; private set; } /// /// Gets the plugin version @@ -284,6 +288,7 @@ namespace MediaBrowser.Common.Plugins public interface IPluginAssembly { - void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion, Guid assemblyId); + void SetAttributes(string assemblyFilePath, string assemblyFileName, Version assemblyVersion); + void SetId(Guid assemblyId); } } diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index d6f0eafc75..fc976b6052 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -17,9 +17,6 @@ namespace MediaBrowser.Model.Dlna [XmlIgnore] public string Id { get; set; } - [XmlIgnore] - public MediaBrowser.Model.Dlna.DeviceProfileType ProfileType { get; set; } - /// /// Gets or sets the identification. /// diff --git a/SharedVersion.cs b/SharedVersion.cs index f946267ea3..1fbacc73d4 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.29.1")] +[assembly: AssemblyVersion("3.2.29.2")] From 234c51ea9a7898e2d14f317a30cc81e13cf2810c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 28 Aug 2017 14:19:23 -0400 Subject: [PATCH 04/73] 3.2.30.1 --- MediaBrowser.Server.Mono/MonoAppHost.cs | 4 +--- MediaBrowser.Server.Mono/Program.cs | 32 +++++++++++++++---------- SharedVersion.cs | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs index e51324ec4d..ded7bb5f3a 100644 --- a/MediaBrowser.Server.Mono/MonoAppHost.cs +++ b/MediaBrowser.Server.Mono/MonoAppHost.cs @@ -12,8 +12,6 @@ using MediaBrowser.IsoMounter; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; -using MediaBrowser.Model.Updates; -using MediaBrowser.Server.Startup.Common; namespace MediaBrowser.Server.Mono { @@ -44,7 +42,7 @@ namespace MediaBrowser.Server.Mono protected override void RestartInternal() { - MainClass.Restart(StartupOptions); + MainClass.Restart(); } protected override List GetAssembliesWithPartsInternal() diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index 443699b5a3..21278e00d7 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -33,6 +33,9 @@ namespace MediaBrowser.Server.Mono private static ILogger _logger; private static IFileSystem FileSystem; + private static readonly TaskCompletionSource ApplicationTaskCompletionSource = new TaskCompletionSource(); + private static bool _restartOnShutdown; + public static void Main(string[] args) { var applicationPath = Assembly.GetEntryAssembly().Location; @@ -63,9 +66,13 @@ namespace MediaBrowser.Server.Mono } finally { - logger.Info("Shutting down"); - + _logger.Info("Disposing app host"); _appHost.Dispose(); + + if (_restartOnShutdown) + { + StartNewInstance(options); + } } } @@ -86,8 +93,6 @@ namespace MediaBrowser.Server.Mono return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath)); } - private static readonly TaskCompletionSource ApplicationTaskCompletionSource = new TaskCompletionSource(); - private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options) { // Allow all https requests @@ -243,11 +248,15 @@ namespace MediaBrowser.Server.Mono ApplicationTaskCompletionSource.SetResult(true); } - public static void Restart(StartupOptions startupOptions) + public static void Restart() { - _logger.Info("Disposing app host"); - _appHost.Dispose(); + _restartOnShutdown = true; + + Shutdown(); + } + private static void StartNewInstance(StartupOptions startupOptions) + { _logger.Info("Starting new instance"); string module = startupOptions.GetOption("-restartpath"); @@ -260,9 +269,9 @@ namespace MediaBrowser.Server.Mono if (!startupOptions.ContainsOption("-restartargs")) { var args = Environment.GetCommandLineArgs() - .Skip(1) - .Select(NormalizeCommandLineArgument) - .ToArray(); + .Skip(1) + .Select(NormalizeCommandLineArgument) + .ToArray(); commandLineArgsString = string.Join(" ", args); } @@ -271,9 +280,6 @@ namespace MediaBrowser.Server.Mono _logger.Info("Arguments: {0}", commandLineArgsString); Process.Start(module, commandLineArgsString); - - _logger.Info("Calling Environment.Exit"); - Environment.Exit(0); } private static string NormalizeCommandLineArgument(string arg) diff --git a/SharedVersion.cs b/SharedVersion.cs index 1fbacc73d4..c32f7bb8de 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.29.2")] +[assembly: AssemblyVersion("3.2.30.1")] From b5f14258e0563c7eeb54ee8e9e00a07056ac9255 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 29 Aug 2017 13:07:04 -0400 Subject: [PATCH 05/73] 3.2.30.2 --- MediaBrowser.Providers/Omdb/OmdbProvider.cs | 2 +- SharedVersion.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 0a95b449c2..e2043faaf3 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -299,7 +299,7 @@ namespace MediaBrowser.Providers.Omdb } } - var url = GetOmdbUrl(string.Format("i={0}&plot=full&tomatoes=true&r=json", imdbParam), cancellationToken); + var url = GetOmdbUrl(string.Format("i={0}&plot=short&tomatoes=true&r=json", imdbParam), cancellationToken); using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { diff --git a/SharedVersion.cs b/SharedVersion.cs index c32f7bb8de..2be59ce39b 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.30.1")] +[assembly: AssemblyVersion("3.2.30.2")] From 8de80d43ba496535aac89d9ec260d8dc2550169b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 30 Aug 2017 14:06:54 -0400 Subject: [PATCH 06/73] update ResolutionNormalizer --- Emby.Server.Implementations/Dto/DtoService.cs | 2 + .../HttpServer/HttpResultFactory.cs | 81 ++++--------------- MediaBrowser.Api/EnvironmentService.cs | 2 +- .../Dlna/ResolutionNormalizer.cs | 6 +- 4 files changed, 25 insertions(+), 66 deletions(-) diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 22793e6529..a0bbd171f8 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -418,6 +418,8 @@ namespace Emby.Server.Implementations.Dto { dto.Type = "Recording"; dto.CanDownload = false; + dto.RunTimeTicks = null; + if (!string.IsNullOrWhiteSpace(dto.SeriesName)) { dto.EpisodeTitle = dto.Name; diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 7bd8fe2bf9..d030068465 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -487,69 +487,8 @@ namespace Emby.Server.Implementations.HttpServer return result; } - var compress = ShouldCompressResponse(requestContext, contentType); - var hasHeaders = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false); - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - - return hasHeaders; - } - - /// - /// Shoulds the compress response. - /// - /// The request context. - /// Type of the content. - /// true if XXXX, false otherwise - private bool ShouldCompressResponse(IRequest requestContext, string contentType) - { - // It will take some work to support compression with byte range requests - if (!string.IsNullOrWhiteSpace(requestContext.Headers.Get("Range"))) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return false; - } - - return true; - } - - /// - /// The us culture - /// - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private async Task GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress) - { var isHeadRequest = options.IsHeadRequest; var factoryFn = options.ContentFactory; - var contentType = options.ContentType; var responseHeaders = options.ResponseHeaders; //var requestedCompressionType = GetCompressionType(requestContext); @@ -558,22 +497,28 @@ namespace Emby.Server.Implementations.HttpServer if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path)) { - return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) + var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) { OnComplete = options.OnComplete, OnError = options.OnError, FileShare = options.FileShare }; + + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; } if (!string.IsNullOrWhiteSpace(rangeHeader)) { var stream = await factoryFn().ConfigureAwait(false); - return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) + var hasHeaders = new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) { OnComplete = options.OnComplete }; + + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; } else { @@ -588,14 +533,22 @@ namespace Emby.Server.Implementations.HttpServer return GetHttpResult(new byte[] { }, contentType, true); } - return new StreamWriter(stream, contentType, _logger) + var hasHeaders = new StreamWriter(stream, contentType, _logger) { OnComplete = options.OnComplete, OnError = options.OnError }; + + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; } } + /// + /// The us culture + /// + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + /// /// Adds the caching responseHeaders. /// diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index bc6101d6cd..400169ac55 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.Api /// IEnumerable{FileSystemEntryInfo}. private IEnumerable GetFileSystemEntries(GetDirectoryContents request) { - var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i => + var entries = _fileSystem.GetFileSystemEntries(request.Path).OrderBy(i => i.FullName).Where(i => { if (!request.IncludeHidden && i.IsHidden) { diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index ae74e255b0..de832314c9 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -58,12 +58,16 @@ namespace MediaBrowser.Model.Dlna private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate) { + ResolutionConfiguration previousOption = null; + foreach (var config in Configurations) { if (outputBitrate <= config.MaxBitrate) { - return config; + return previousOption ?? config; } + + previousOption = config; } return null; From 0f23c7cfc1372ead03ab9b818e698441d4d53bd3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 30 Aug 2017 14:52:29 -0400 Subject: [PATCH 07/73] 3.2.30.3 --- .../ApplicationHost.cs | 4 +- .../HttpServer/HttpListenerHost.cs | 67 +++++++++---------- .../HttpServer/LoggerUtils.cs | 20 ++++-- .../HttpServer/Security/AuthService.cs | 5 +- .../Security/AuthorizationContext.cs | 6 +- .../ServerManager/ServerManager.cs | 4 +- .../Services/ServiceExec.cs | 25 +++++-- .../Services/ServiceMethod.cs | 7 -- .../Services/StringMapTypeDeserializer.cs | 10 ++- MediaBrowser.Api/Dlna/DlnaServerService.cs | 36 +++++++--- .../Net/AuthenticatedAttribute.cs | 5 +- MediaBrowser.Controller/Net/IHttpServer.cs | 4 +- MediaBrowser.Controller/Net/IServerManager.cs | 2 +- SharedVersion.cs | 2 +- 14 files changed, 117 insertions(+), 80 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3454451022..a9d3247e65 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1614,7 +1614,7 @@ namespace Emby.Server.Implementations { try { - ServerManager.Start(GetUrlPrefixes()); + ServerManager.Start(GetUrlPrefixes().ToArray()); return; } catch (Exception ex) @@ -1631,7 +1631,7 @@ namespace Emby.Server.Implementations try { - ServerManager.Start(GetUrlPrefixes()); + ServerManager.Start(GetUrlPrefixes().ToArray()); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index f1fea2085b..9297362f9e 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -10,7 +10,6 @@ using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer.SocketSharp; using Emby.Server.Implementations.Services; using MediaBrowser.Common.Net; @@ -34,7 +33,7 @@ namespace Emby.Server.Implementations.HttpServer private string DefaultRedirectPath { get; set; } private readonly ILogger _logger; - public IEnumerable UrlPrefixes { get; private set; } + public string[] UrlPrefixes { get; private set; } private readonly List _restServices = new List(); @@ -62,8 +61,8 @@ namespace Emby.Server.Implementations.HttpServer private readonly Func> _funcParseFn; private readonly bool _enableDualModeSockets; - public List> RequestFilters { get; set; } - public List> ResponseFilters { get; set; } + public Action[] RequestFilters { get; set; } + public Action[] ResponseFilters { get; set; } private readonly Dictionary ServiceOperationsMap = new Dictionary(); public static HttpListenerHost Instance { get; protected set; } @@ -95,8 +94,8 @@ namespace Emby.Server.Implementations.HttpServer _logger = logger; - RequestFilters = new List>(); - ResponseFilters = new List>(); + RequestFilters = new Action[] { }; + ResponseFilters = new Action[] { }; } public string GlobalResponse { get; set; } @@ -135,7 +134,9 @@ namespace Emby.Server.Implementations.HttpServer //Exec all RequestFilter attributes with Priority < 0 var attributes = GetRequestFilterAttributes(requestDto.GetType()); var i = 0; - for (; i < attributes.Length && attributes[i].Priority < 0; i++) + var count = attributes.Count; + + for (; i < count && attributes[i].Priority < 0; i++) { var attribute = attributes[i]; attribute.RequestFilter(req, res, requestDto); @@ -148,7 +149,7 @@ namespace Emby.Server.Implementations.HttpServer } //Exec remaining RequestFilter attributes with Priority >= 0 - for (; i < attributes.Length && attributes[i].Priority >= 0; i++) + for (; i < count && attributes[i].Priority >= 0; i++) { var attribute = attributes[i]; attribute.RequestFilter(req, res, requestDto); @@ -167,7 +168,7 @@ namespace Emby.Server.Implementations.HttpServer ServiceOperationsMap[requestType] = serviceType; } - private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType) + private List GetRequestFilterAttributes(Type requestDtoType) { var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType().ToList(); @@ -179,24 +180,7 @@ namespace Emby.Server.Implementations.HttpServer attributes.Sort((x, y) => x.Priority - y.Priority); - return attributes.ToArray(attributes.Count); - } - - /// - /// Starts the Web Service - /// - private void StartListener() - { - WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First()); - - _listener = GetListener(); - - _listener.WebSocketConnected = OnWebSocketConnected; - _listener.WebSocketConnecting = OnWebSocketConnecting; - _listener.ErrorHandler = ErrorHandler; - _listener.RequestHandler = RequestHandler; - - _listener.Start(UrlPrefixes); + return attributes; } public static string GetHandlerPathIfAny(string listenerUrl) @@ -698,13 +682,18 @@ namespace Emby.Server.Implementations.HttpServer ServiceController.Init(this, types); - var requestFilters = _appHost.GetExports().ToList(); - foreach (var filter in requestFilters) + var list = new List>(); + foreach (var filter in _appHost.GetExports()) { - RequestFilters.Add(filter.Filter); + list.Add(filter.Filter); } - ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); + RequestFilters = list.ToArray(); + + ResponseFilters = new Action[] + { + new ResponseFilter(_logger).FilterResponse + }; } public RouteAttribute[] GetRouteAttributes(Type requestType) @@ -819,10 +808,20 @@ namespace Emby.Server.Implementations.HttpServer GC.SuppressFinalize(this); } - public void StartServer(IEnumerable urlPrefixes) + public void StartServer(string[] urlPrefixes) { - UrlPrefixes = urlPrefixes.ToList(); - StartListener(); + UrlPrefixes = urlPrefixes; + + WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]); + + _listener = GetListener(); + + _listener.WebSocketConnected = OnWebSocketConnected; + _listener.WebSocketConnecting = OnWebSocketConnecting; + _listener.ErrorHandler = ErrorHandler; + _listener.RequestHandler = RequestHandler; + + _listener.Start(UrlPrefixes); } } } \ No newline at end of file diff --git a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs index de30dc30a8..46bb4c7f94 100644 --- a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs @@ -1,10 +1,8 @@ using MediaBrowser.Model.Logging; using System; using System.Globalization; -using System.Linq; using MediaBrowser.Model.Services; using SocketHttpListener.Net; -using MediaBrowser.Model.Extensions; namespace Emby.Server.Implementations.HttpServer { @@ -30,7 +28,20 @@ namespace Emby.Server.Implementations.HttpServer } else { - var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray(headers.Count)); + var headerText = string.Empty; + var index = 0; + + foreach (var i in headers) + { + if (index > 0) + { + headerText += ", "; + } + + headerText += i.Name + "=" + i.Value; + + index++; + } logger.Info("HTTP {0} {1}. {2}", method, url, headerText); } @@ -49,7 +60,8 @@ namespace Emby.Server.Implementations.HttpServer var durationMs = duration.TotalMilliseconds; var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms"; - var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray()); + //var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray()); + var headerText = string.Empty; logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText); } } diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs index 4d00c9b195..500bdc61eb 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -7,7 +7,6 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; using System; -using System.Collections.Generic; using System.Linq; namespace Emby.Server.Implementations.HttpServer.Security @@ -78,7 +77,7 @@ namespace Emby.Server.Implementations.HttpServer.Security if (!IsExemptFromRoles(auth, authAttribtues, info)) { - var roles = authAttribtues.GetRoles().ToList(); + var roles = authAttribtues.GetRoles(); ValidateRoles(roles, user); } @@ -162,7 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security return false; } - private void ValidateRoles(List roles, User user) + private void ValidateRoles(string[] roles, User user) { if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) { diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index ede85fb67d..f402777789 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -3,8 +3,8 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using System; using System.Collections.Generic; -using System.Linq; using MediaBrowser.Model.Services; +using System.Linq; namespace Emby.Server.Implementations.HttpServer.Security { @@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer.Security AccessToken = token }); - var tokenInfo = result.Items.FirstOrDefault(); + var tokenInfo = result.Items.Length > 0 ? result.Items[0] : null; if (tokenInfo != null) { @@ -161,7 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security // There should be at least to parts if (parts.Length != 2) return null; - var acceptedNames = new[] { "MediaBrowser", "Emby"}; + var acceptedNames = new[] { "MediaBrowser", "Emby" }; // It has to be a digest request if (!acceptedNames.Contains(parts[0] ?? string.Empty, StringComparer.OrdinalIgnoreCase)) diff --git a/Emby.Server.Implementations/ServerManager/ServerManager.cs b/Emby.Server.Implementations/ServerManager/ServerManager.cs index 7cd94c5260..b267f928b6 100644 --- a/Emby.Server.Implementations/ServerManager/ServerManager.cs +++ b/Emby.Server.Implementations/ServerManager/ServerManager.cs @@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.ServerManager /// /// Starts this instance. /// - public void Start(IEnumerable urlPrefixes) + public void Start(string[] urlPrefixes) { ReloadHttpServer(urlPrefixes); } @@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.ServerManager /// /// Restarts the Http Server, or starts it if not currently running /// - private void ReloadHttpServer(IEnumerable urlPrefixes) + private void ReloadHttpServer(string[] urlPrefixes) { _logger.Info("Loading Http Server"); diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index 4a2199c89d..fa9e26f28f 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -24,19 +24,33 @@ namespace Emby.Server.Implementations.Services "POLL", "SUBSCRIBE", "UNSUBSCRIBE" }); - public static IEnumerable GetActions(this Type serviceType) + public static List GetActions(this Type serviceType) { - foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic)) + var list = new List(); + + foreach (var mi in serviceType.GetRuntimeMethods()) { + if (!mi.IsPublic) + { + continue; + } + + if (mi.IsStatic) + { + continue; + } + if (mi.GetParameters().Length != 1) continue; var actionName = mi.Name; - if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase) && !string.Equals(actionName, ServiceMethod.AnyAction, StringComparison.OrdinalIgnoreCase)) + if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase)) continue; - yield return mi; + list.Add(mi); } + + return list; } } @@ -59,8 +73,7 @@ namespace Emby.Server.Implementations.Services var actionName = request.Verb ?? "POST"; ServiceMethod actionContext; - if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext) - || ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.AnyKey(serviceType, requestName), out actionContext)) + if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext)) { if (actionContext.RequestFilters != null) { diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs index bcbc6fb572..fa2dd43d06 100644 --- a/Emby.Server.Implementations/Services/ServiceMethod.cs +++ b/Emby.Server.Implementations/Services/ServiceMethod.cs @@ -4,8 +4,6 @@ namespace Emby.Server.Implementations.Services { public class ServiceMethod { - public const string AnyAction = "ANY"; - public string Id { get; set; } public ActionInvokerFn ServiceAction { get; set; } @@ -15,10 +13,5 @@ namespace Emby.Server.Implementations.Services { return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName; } - - public static string AnyKey(Type serviceType, string requestDtoName) - { - return Key(serviceType, AnyAction, requestDtoName); - } } } \ No newline at end of file diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs index fc1cf4ed99..2233bf918b 100644 --- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs +++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; namespace Emby.Server.Implementations.Services @@ -64,11 +63,16 @@ namespace Emby.Server.Implementations.Services if (instance == null) instance = _CreateInstanceFn(type); - foreach (var pair in keyValuePairs.Where(x => !string.IsNullOrEmpty(x.Value))) + foreach (var pair in keyValuePairs) { propertyName = pair.Key; propertyTextValue = pair.Value; + if (string.IsNullOrEmpty(propertyTextValue)) + { + continue; + } + if (!propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry)) { if (propertyName == "v") @@ -115,7 +119,7 @@ namespace Emby.Server.Implementations.Services { public static Action GetSetPropertyMethod(Type type, PropertyInfo propertyInfo) { - if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Any()) return null; + if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0) return null; var setMethodInfo = propertyInfo.SetMethod; return (instance, value) => setMethodInfo.Invoke(instance, new[] { value }); diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index 389244aa96..cbef6e5b3b 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -70,24 +70,27 @@ namespace MediaBrowser.Api.Dlna public Stream RequestStream { get; set; } } - [Route("/Dlna/{UuId}/mediareceiverregistrar/events", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/mediareceiverregistrar/events", "SUBSCRIBE", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/mediareceiverregistrar/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")] public class ProcessMediaReceiverRegistrarEventRequest { - [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")] + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")] public string UuId { get; set; } } - [Route("/Dlna/{UuId}/contentdirectory/events", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/contentdirectory/events", "SUBSCRIBE", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/contentdirectory/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")] public class ProcessContentDirectoryEventRequest { - [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")] + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")] public string UuId { get; set; } } - [Route("/Dlna/{UuId}/connectionmanager/events", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/connectionmanager/events", "SUBSCRIBE", Summary = "Processes an event subscription request")] + [Route("/Dlna/{UuId}/connectionmanager/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")] public class ProcessConnectionManagerEventRequest { - [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")] + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")] public string UuId { get; set; } } @@ -200,17 +203,32 @@ namespace MediaBrowser.Api.Dlna } } - public object Any(ProcessContentDirectoryEventRequest request) + public object Subscribe(ProcessContentDirectoryEventRequest request) { return ProcessEventRequest(_contentDirectory); } - public object Any(ProcessConnectionManagerEventRequest request) + public object Subscribe(ProcessConnectionManagerEventRequest request) { return ProcessEventRequest(_connectionManager); } - public object Any(ProcessMediaReceiverRegistrarEventRequest request) + public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request) + { + return ProcessEventRequest(_mediaReceiverRegistrar); + } + + public object Unsubscribe(ProcessContentDirectoryEventRequest request) + { + return ProcessEventRequest(_contentDirectory); + } + + public object Unsubscribe(ProcessConnectionManagerEventRequest request) + { + return ProcessEventRequest(_connectionManager); + } + + public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request) { return ProcessEventRequest(_mediaReceiverRegistrar); } diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index 81e294069f..6ded3761fc 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using MediaBrowser.Model.Services; namespace MediaBrowser.Controller.Net @@ -50,7 +49,7 @@ namespace MediaBrowser.Controller.Net get { return 0; } } - public IEnumerable GetRoles() + public string[] GetRoles() { return (Roles ?? string.Empty).Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries); } @@ -61,6 +60,6 @@ namespace MediaBrowser.Controller.Net bool EscapeParentalControl { get; } bool AllowBeforeStartupWizard { get; } - IEnumerable GetRoles(); + string[] GetRoles(); } } diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index f319244dae..f41572b454 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Net /// Gets the URL prefix. /// /// The URL prefix. - IEnumerable UrlPrefixes { get; } + string[] UrlPrefixes { get; } /// /// Starts the specified server name. /// /// The URL prefixes. - void StartServer(IEnumerable urlPrefixes); + void StartServer(string[] urlPrefixes); /// /// Stops this instance. diff --git a/MediaBrowser.Controller/Net/IServerManager.cs b/MediaBrowser.Controller/Net/IServerManager.cs index 202df29824..a84c48c5b1 100644 --- a/MediaBrowser.Controller/Net/IServerManager.cs +++ b/MediaBrowser.Controller/Net/IServerManager.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Net /// Starts this instance. /// /// The URL prefixes. - void Start(IEnumerable urlPrefixes); + void Start(string[] urlPrefixes); /// /// Sends a message to all clients currently connected via a web socket diff --git a/SharedVersion.cs b/SharedVersion.cs index 2be59ce39b..22a7f2a838 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.30.2")] +[assembly: AssemblyVersion("3.2.30.3")] From dd9404ebc6e2e03bb4f0135e48a59211252615d9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 30 Aug 2017 23:49:38 -0400 Subject: [PATCH 08/73] update skiasharp to 1.58.1 --- Emby.Drawing.Skia/Emby.Drawing.Skia.csproj | 2 +- Emby.Drawing.Skia/SkiaEncoder.cs | 35 +++-- Emby.Drawing.Skia/packages.config | 2 +- Emby.Drawing/ImageProcessor.cs | 14 +- .../HttpServer/HttpListenerHost.cs | 17 --- .../Services/ServiceController.cs | 9 +- .../Services/ServiceExec.cs | 6 +- .../Services/ServicePath.cs | 124 +++++++++--------- .../MediaBrowser.Server.Mono.csproj | 10 +- MediaBrowser.Server.Mono/packages.config | 2 +- .../MediaBrowser.ServerApplication.csproj | 23 +++- .../packages.config | 2 +- .../x64/libSkiaSharp.dll.REMOVED.git-id | 1 - 13 files changed, 128 insertions(+), 119 deletions(-) delete mode 100644 MediaBrowser.ServerApplication/x64/libSkiaSharp.dll.REMOVED.git-id diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj index a4ab19f838..f2b32d52cb 100644 --- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj +++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj @@ -64,7 +64,7 @@ - ..\packages\SkiaSharp.1.58.0\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll + ..\packages\SkiaSharp.1.58.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs index 77ab1919aa..24f586d96e 100644 --- a/Emby.Drawing.Skia/SkiaEncoder.cs +++ b/Emby.Drawing.Skia/SkiaEncoder.cs @@ -195,12 +195,26 @@ namespace Emby.Drawing.Skia { var codec = SKCodec.Create(stream); + if (codec == null) + { + origin = SKCodecOrigin.TopLeft; + return null; + } + // create the bitmap var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); - // decode - codec.GetPixels(bitmap.Info, bitmap.GetPixels()); - origin = codec.Origin; + if (bitmap != null) + { + // decode + codec.GetPixels(bitmap.Info, bitmap.GetPixels()); + + origin = codec.Origin; + } + else + { + origin = SKCodecOrigin.TopLeft; + } return bitmap; } @@ -239,7 +253,7 @@ namespace Emby.Drawing.Skia return Decode(path, forceAnalyzeBitmap, out origin); } - private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation) + private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient) { SKCodecOrigin origin; @@ -247,11 +261,14 @@ namespace Emby.Drawing.Skia { var bitmap = GetBitmap(path, cropWhitespace, true, out origin); - if (origin != SKCodecOrigin.TopLeft) + if (bitmap != null) { - using (bitmap) + if (origin != SKCodecOrigin.TopLeft) { - return RotateAndFlip(bitmap, origin); + using (bitmap) + { + return RotateAndFlip(bitmap, origin); + } } } @@ -357,11 +374,11 @@ namespace Emby.Drawing.Skia var blur = options.Blur ?? 0; var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); - using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation)) + using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient)) { if (bitmap == null) { - throw new Exception(string.Format("Skia unable to read image {0}", inputPath)); + throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath)); } //_logger.Info("Color type {0}", bitmap.Info.ColorType); diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config index 9d21b2864a..2b9b0aee43 100644 --- a/Emby.Drawing.Skia/packages.config +++ b/Emby.Drawing.Skia/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 8f3042e2ad..356343baee 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -296,11 +296,6 @@ namespace Emby.Drawing var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath)); _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath)); - if (item == null && string.Equals(options.ItemType, typeof(Photo).Name, StringComparison.OrdinalIgnoreCase)) - { - item = _libraryManager().GetItemById(options.ItemId); - } - if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath)) { options.CropWhiteSpace = false; @@ -321,6 +316,15 @@ namespace Emby.Drawing return new Tuple(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath)); } + catch (ArgumentOutOfRangeException ex) + { + // Decoder failed to decode it +#if DEBUG + _logger.ErrorException("Error encoding image", ex); +#endif + // Just spit out the original file if all the options are default + return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); + } catch (Exception ex) { // If it fails for whatever reason, return the original image diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 9297362f9e..a9ce513247 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -710,13 +710,6 @@ namespace Emby.Server.Implementations.HttpServer Summary = route.Summary }); - routes.Add(new RouteAttribute(NormalizeRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs) { Notes = route.Notes, @@ -773,16 +766,6 @@ namespace Emby.Server.Implementations.HttpServer return "emby/emby/" + path; } - private string NormalizeRoutePath(string path) - { - if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - { - return "/mediabrowser" + path; - } - - return "mediabrowser/" + path; - } - private bool _disposed; private readonly object _disposeLock = new object(); protected virtual void Dispose(bool disposing) diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index c3970b22f6..4dc14a1934 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -75,11 +75,7 @@ namespace Emby.Server.Implementations.Services var attrs = appHost.GetRouteAttributes(requestType); foreach (RouteAttribute attr in attrs) { - var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, attr.Path, attr.Verbs, attr.Summary, attr.Notes); - - if (!restPath.IsValid) - throw new NotSupportedException(string.Format( - "RestPath '{0}' on Type '{1}' is not Valid", attr.Path, requestType.GetMethodName())); + var restPath = new RestPath(appHost.CreateInstance, appHost.GetParseFn, requestType, attr.Path, attr.Verbs, attr.Summary); RegisterRestPath(restPath); } @@ -92,8 +88,7 @@ namespace Emby.Server.Implementations.Services if (!restPath.Path.StartsWith("/")) throw new ArgumentException(string.Format("Route '{0}' on '{1}' must start with a '/'", restPath.Path, restPath.RequestType.GetMethodName())); if (restPath.Path.IndexOfAny(InvalidRouteChars) != -1) - throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. " + - "See https://github.com/ServiceStack/ServiceStack/wiki/Routing for info on valid routes.", restPath.Path, restPath.RequestType.GetMethodName())); + throw new ArgumentException(string.Format("Route '{0}' on '{1}' contains invalid chars. ", restPath.Path, restPath.RequestType.GetMethodName())); List pathsAtFirstMatch; if (!RestPathMap.TryGetValue(restPath.FirstMatchHashKey, out pathsAtFirstMatch)) diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index fa9e26f28f..7971c6781d 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Services { public static class ServiceExecExtensions { - public static HashSet AllVerbs = new HashSet(new[] { + public static string[] AllVerbs = new[] { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", // RFC 2616 "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", // RFC 2518 "VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT", @@ -22,7 +22,9 @@ namespace Emby.Server.Implementations.Services "SEARCH", // https://datatracker.ietf.org/doc/draft-reschke-webdav-search/ "BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "NOTIFY", "POLL", "SUBSCRIBE", "UNSUBSCRIBE" - }); + }; + + public static HashSet AllVerbsSet = new HashSet(AllVerbs); public static List GetActions(this Type serviceType) { diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index da5e74f1fb..df5d713747 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -21,8 +21,6 @@ namespace Emby.Server.Implementations.Services readonly bool[] componentsWithSeparators; private readonly string restPath; - private readonly string allowedVerbs; - private readonly bool allowsAllVerbs; public bool IsWildCardPath { get; private set; } private readonly string[] literalsToMatch; @@ -46,15 +44,7 @@ namespace Emby.Server.Implementations.Services /// public int TotalComponentsCount { get; set; } - public string[] Verbs - { - get - { - return allowsAllVerbs - ? new[] { "ANY" } - : AllowedVerbs.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - } - } + public string[] Verbs { get; private set; } public Type RequestType { get; private set; } @@ -62,19 +52,11 @@ namespace Emby.Server.Implementations.Services public string Summary { get; private set; } - public string Notes { get; private set; } - - public bool AllowsAllVerbs { get { return this.allowsAllVerbs; } } - - public string AllowedVerbs { get { return this.allowedVerbs; } } - public int Priority { get; set; } //passed back to RouteAttribute public static string[] GetPathPartsForMatching(string pathInfo) { - var parts = pathInfo.ToLower().Split(PathSeperatorChar) - .Where(x => !String.IsNullOrEmpty(x)).ToArray(); - return parts; + return pathInfo.ToLower().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); } public static List GetFirstMatchHashKeys(string[] pathPartsForMatching) @@ -109,18 +91,13 @@ namespace Emby.Server.Implementations.Services return list; } - public RestPath(Func createInstanceFn, Func> getParseFn, Type requestType, string path, string verbs, string summary = null, string notes = null) + public RestPath(Func createInstanceFn, Func> getParseFn, Type requestType, string path, string verbs, string summary = null) { this.RequestType = requestType; this.Summary = summary; - this.Notes = notes; this.restPath = path; - this.allowsAllVerbs = verbs == null || String.Equals(verbs, WildCard, StringComparison.OrdinalIgnoreCase); - if (!this.allowsAllVerbs) - { - this.allowedVerbs = verbs.ToUpper(); - } + this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpper().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); var componentsList = new List(); @@ -153,7 +130,6 @@ namespace Emby.Server.Implementations.Services this.PathComponentsCount = this.componentsWithSeparators.Length; string firstLiteralMatch = null; - var sbHashKey = new StringBuilder(); for (var i = 0; i < components.Length; i++) { var component = components[i]; @@ -172,7 +148,6 @@ namespace Emby.Server.Implementations.Services else { this.literalsToMatch[i] = component.ToLower(); - sbHashKey.Append(i + PathSeperatorChar.ToString() + this.literalsToMatch); if (firstLiteralMatch == null) { @@ -198,9 +173,6 @@ namespace Emby.Server.Implementations.Services ? this.PathComponentsCount + PathSeperator + firstLiteralMatch : WildCardChar + PathSeperator + firstLiteralMatch; - this.IsValid = sbHashKey.Length > 0; - this.UniqueMatchHashKey = sbHashKey.ToString(); - this.typeDeserializer = new StringMapTypeDeserializer(createInstanceFn, getParseFn, this.RequestType); RegisterCaseInsenstivePropertyNameMappings(); } @@ -220,26 +192,46 @@ namespace Emby.Server.Implementations.Services }; - private static List _excludeTypes = new List { typeof(Stream) }; + private static Type excludeType = typeof(Stream); - internal static PropertyInfo[] GetSerializableProperties(Type type) + internal static List GetSerializableProperties(Type type) { - var properties = GetPublicProperties(type); - var readableProperties = properties.Where(x => x.GetMethod != null); + var list = new List(); + var props = GetPublicProperties(type); - // else return those properties that are not decorated with IgnoreDataMember - return readableProperties - .Where(prop => prop.GetCustomAttributes(true) - .All(attr => + foreach (var prop in props) + { + if (prop.GetMethod == null) + { + continue; + } + + if (excludeType == prop.PropertyType) + { + continue; + } + + var ignored = false; + foreach (var attr in prop.GetCustomAttributes(true)) + { + if (IgnoreAttributesNamed.Contains(attr.GetType().Name)) { - var name = attr.GetType().Name; - return !IgnoreAttributesNamed.Contains(name); - })) - .Where(prop => !_excludeTypes.Contains(prop.PropertyType)) - .ToArray(); + ignored = true; + break; + } + } + + if (!ignored) + { + list.Add(prop); + } + } + + // else return those properties that are not decorated with IgnoreDataMember + return list; } - private static PropertyInfo[] GetPublicProperties(Type type) + private static List GetPublicProperties(Type type) { if (type.GetTypeInfo().IsInterface) { @@ -269,12 +261,19 @@ namespace Emby.Server.Implementations.Services propertyInfos.InsertRange(0, newPropertyInfos); } - return propertyInfos.ToArray(propertyInfos.Count); + return propertyInfos; } - return GetTypesPublicProperties(type) - .Where(t => t.GetIndexParameters().Length == 0) // ignore indexed properties - .ToArray(); + var list = new List(); + + foreach (var t in GetTypesPublicProperties(type)) + { + if (t.GetIndexParameters().Length == 0) + { + list.Add(t); + } + } + return list; } private static PropertyInfo[] GetTypesPublicProperties(Type subType) @@ -289,16 +288,11 @@ namespace Emby.Server.Implementations.Services return pis.ToArray(pis.Count); } - - public bool IsValid { get; set; } - /// /// Provide for quick lookups based on hashes that can be determined from a request url /// public string FirstMatchHashKey { get; private set; } - public string UniqueMatchHashKey { get; private set; } - private readonly StringMapTypeDeserializer typeDeserializer; private readonly Dictionary propertyNamesMap = new Dictionary(); @@ -321,8 +315,14 @@ namespace Emby.Server.Implementations.Services score += Math.Max((10 - VariableArgsCount), 1) * 100; //Exact verb match is better than ANY - var exactVerb = String.Equals(httpMethod, AllowedVerbs, StringComparison.OrdinalIgnoreCase); - score += exactVerb ? 10 : 1; + if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase)) + { + score += 10; + } + else + { + score += 1; + } return score; } @@ -346,7 +346,7 @@ namespace Emby.Server.Implementations.Services return false; } - if (!this.allowsAllVerbs && !StringContains(this.allowedVerbs, httpMethod)) + if (!Verbs.Contains(httpMethod, StringComparer.OrdinalIgnoreCase)) { //logger.Info("allowsAllVerbs mismatch for {0} for {1} allowedverbs {2}", httpMethod, string.Join("/", withPathInfoParts), this.allowedVerbs); return false; @@ -457,8 +457,7 @@ namespace Emby.Server.Implementations.Services public object CreateRequest(string pathInfo, Dictionary queryStringAndFormData, object fromInstance) { - var requestComponents = pathInfo.Split(PathSeperatorChar) - .Where(x => !String.IsNullOrEmpty(x)).ToArray(); + var requestComponents = pathInfo.Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); ExplodeComponents(ref requestComponents); @@ -555,10 +554,5 @@ namespace Emby.Server.Implementations.Services return this.typeDeserializer.PopulateFromMap(fromInstance, requestKeyValuesMap); } - - public override int GetHashCode() - { - return UniqueMatchHashKey.GetHashCode(); - } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj index 7ddafb6360..04c4b50ef4 100644 --- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -63,8 +63,7 @@ ..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll - ..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll - True + ..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll ..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll @@ -196,4 +195,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config index 525a0098c8..cff873f1f7 100644 --- a/MediaBrowser.Server.Mono/packages.config +++ b/MediaBrowser.Server.Mono/packages.config @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 15abaaa62c..df2534d138 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -85,7 +85,7 @@ ..\packages\SimpleInjector.4.0.8\lib\net45\SimpleInjector.dll - ..\packages\SkiaSharp.1.58.0\lib\net45\SkiaSharp.dll + ..\packages\SkiaSharp.1.58.1\lib\net45\SkiaSharp.dll ..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll @@ -162,6 +162,14 @@ + + x64\libSkiaSharp.dll + PreserveNewest + + + x86\libSkiaSharp.dll + PreserveNewest + MediaBrowser.InstallUtil.dll PreserveNewest @@ -174,17 +182,11 @@ MediaBrowser.Updater.exe PreserveNewest - - PreserveNewest - PreserveNewest - - PreserveNewest - PreserveNewest @@ -268,6 +270,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +