diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index 4a36a16eb6..92d388e3b2 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.TV; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Xml; @@ -31,6 +32,7 @@ namespace Emby.Dlna.ContentDirectory private readonly IUserViewManager _userViewManager; private readonly Func _mediaEncoder; protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; + private readonly ITVSeriesManager _tvSeriesManager; public ContentDirectory(IDlnaManager dlna, IUserDataManager userDataManager, @@ -39,7 +41,7 @@ namespace Emby.Dlna.ContentDirectory IServerConfigurationManager config, IUserManager userManager, ILogger logger, - IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager) : base(logger, httpClient) { _dlna = dlna; @@ -54,6 +56,7 @@ namespace Emby.Dlna.ContentDirectory _userViewManager = userViewManager; _mediaEncoder = mediaEncoder; XmlReaderSettingsFactory = xmlReaderSettingsFactory; + _tvSeriesManager = tvSeriesManager; } private int SystemUpdateId @@ -97,7 +100,8 @@ namespace Emby.Dlna.ContentDirectory _mediaSourceManager, _userViewManager, _mediaEncoder(), - XmlReaderSettingsFactory) + XmlReaderSettingsFactory, + _tvSeriesManager) .ProcessControlRequest(request); } diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 9345a1df71..4d82b6b250 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -27,6 +27,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Playlists; +using MediaBrowser.Controller.TV; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Xml; @@ -40,6 +41,7 @@ namespace Emby.Dlna.ContentDirectory private readonly IServerConfigurationManager _config; private readonly User _user; private readonly IUserViewManager _userViewManager; + private readonly ITVSeriesManager _tvSeriesManager; private const string NS_DC = "http://purl.org/dc/elements/1.1/"; private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"; @@ -53,7 +55,7 @@ namespace Emby.Dlna.ContentDirectory private readonly DeviceProfile _profile; - public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager) : base(config, logger, xmlReaderSettingsFactory) { _libraryManager = libraryManager; @@ -62,6 +64,7 @@ namespace Emby.Dlna.ContentDirectory _systemUpdateId = systemUpdateId; _channelManager = channelManager; _userViewManager = userViewManager; + _tvSeriesManager = tvSeriesManager; _profile = profile; _config = config; @@ -488,6 +491,14 @@ namespace Emby.Dlna.ContentDirectory { return GetMusicFolders(item, user, stubType, sort, startIndex, limit); } + if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return GetMovieFolders(item, user, stubType, sort, startIndex, limit); + } + if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return GetTvFolders(item, user, stubType, sort, startIndex, limit); + } if (stubType.HasValue) { @@ -656,6 +667,231 @@ namespace Emby.Dlna.ContentDirectory }; } + private QueryResult GetMovieFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + { + var query = new InternalItemsQuery(user) + { + StartIndex = startIndex, + Limit = limit + }; + SetSorting(query, sort, false); + + if (stubType.HasValue && stubType.Value == StubType.ContinueWatching) + { + return GetMovieContinueWatching(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Latest) + { + return GetMovieLatest(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Movies) + { + return GetMovieMovies(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Collections) + { + return GetMovieCollections(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Favorites) + { + return GetMovieFavorites(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Genres) + { + return GetGenres(item, user, query); + } + + var list = new List(); + + list.Add(new ServerItem(item) + { + StubType = StubType.ContinueWatching + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Latest + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Movies + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Collections + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Favorites + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Genres + }); + + return new QueryResult + { + Items = list.ToArray(), + TotalRecordCount = list.Count + }; + } + + private QueryResult GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + { + var query = new InternalItemsQuery(user) + { + StartIndex = startIndex, + Limit = limit + }; + SetSorting(query, sort, false); + + if (stubType.HasValue && stubType.Value == StubType.ContinueWatching) + { + return GetMovieContinueWatching(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.NextUp) + { + return GetNextUp(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Latest) + { + return GetTvLatest(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Series) + { + return GetSeries(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.FavoriteSeries) + { + return GetFavoriteSeries(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.FavoriteEpisodes) + { + return GetFavoriteEpisodes(item, user, query); + } + + if (stubType.HasValue && stubType.Value == StubType.Genres) + { + return GetGenres(item, user, query); + } + + var list = new List(); + + list.Add(new ServerItem(item) + { + StubType = StubType.ContinueWatching + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.NextUp + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Latest + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Series + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.FavoriteSeries + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.FavoriteEpisodes + }); + + list.Add(new ServerItem(item) + { + StubType = StubType.Genres + }); + + return new QueryResult + { + Items = list.ToArray(), + TotalRecordCount = list.Count + }; + } + + private QueryResult GetMovieContinueWatching(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + + query.OrderBy = new List> + { + new Tuple (ItemSortBy.DatePlayed, SortOrder.Descending), + new Tuple (ItemSortBy.SortName, SortOrder.Ascending) + }; + + query.IsResumable = true; + query.Limit = 10; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + + private QueryResult GetSeries(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + + query.IncludeItemTypes = new[] { typeof(Series).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + + private QueryResult GetMovieMovies(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + + query.IncludeItemTypes = new[] { typeof(Movie).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + + private QueryResult GetMovieCollections(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + //query.Parent = parent; + query.SetUser(user); + + query.IncludeItemTypes = new[] { typeof(BoxSet).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + private QueryResult GetMusicAlbums(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; @@ -695,6 +931,45 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } + private QueryResult GetFavoriteSeries(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + query.IsFavorite = true; + query.IncludeItemTypes = new[] { typeof(Series).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + + private QueryResult GetFavoriteEpisodes(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + query.IsFavorite = true; + query.IncludeItemTypes = new[] { typeof(Episode).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + + private QueryResult GetMovieFavorites(BaseItem parent, User user, InternalItemsQuery query) + { + query.Recursive = true; + query.Parent = parent; + query.SetUser(user); + query.IsFavorite = true; + query.IncludeItemTypes = new[] { typeof(Movie).Name }; + + var result = _libraryManager.GetItemsResult(query); + + return ToResult(result); + } + private QueryResult GetFavoriteAlbums(BaseItem parent, User user, InternalItemsQuery query) { query.Recursive = true; @@ -708,6 +983,24 @@ namespace Emby.Dlna.ContentDirectory return ToResult(result); } + private QueryResult GetGenres(BaseItem parent, User user, InternalItemsQuery query) + { + var genresResult = _libraryManager.GetGenres(new InternalItemsQuery(user) + { + AncestorIds = new[] { parent.Id.ToString("N") }, + StartIndex = query.StartIndex, + Limit = query.Limit + }); + + var result = new QueryResult + { + TotalRecordCount = genresResult.TotalRecordCount, + Items = genresResult.Items.Select(i => i.Item1).ToArray() + }; + + return ToResult(result); + } + private QueryResult GetMusicGenres(BaseItem parent, User user, InternalItemsQuery query) { var genresResult = _libraryManager.GetMusicGenres(new InternalItemsQuery(user) @@ -810,6 +1103,55 @@ namespace Emby.Dlna.ContentDirectory return ToResult(items); } + private QueryResult GetNextUp(BaseItem parent, User user, InternalItemsQuery query) + { + query.SortBy = new string[] { }; + + var result = _tvSeriesManager.GetNextUp(new NextUpQuery + { + Limit = query.Limit, + StartIndex = query.StartIndex, + UserId = query.User.Id.ToString("N") + + }, new List { (Folder)parent }, query.DtoOptions); + + return ToResult(result); + } + + private QueryResult GetTvLatest(BaseItem parent, User user, InternalItemsQuery query) + { + query.SortBy = new string[] { }; + + var items = _userViewManager.GetLatestItems(new LatestItemsQuery + { + UserId = user.Id.ToString("N"), + Limit = 50, + IncludeItemTypes = new[] { typeof(Episode).Name }, + ParentId = parent == null ? null : parent.Id.ToString("N"), + GroupItems = true + + }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList(); + + return ToResult(items); + } + + private QueryResult GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query) + { + query.SortBy = new string[] { }; + + var items = _userViewManager.GetLatestItems(new LatestItemsQuery + { + UserId = user.Id.ToString("N"), + Limit = 50, + IncludeItemTypes = new[] { typeof(Movie).Name }, + ParentId = parent == null ? null : parent.Id.ToString("N"), + GroupItems = true + + }, query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null).ToList(); + + return ToResult(items); + } + private QueryResult GetMusicArtistItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) @@ -942,65 +1284,16 @@ namespace Emby.Dlna.ContentDirectory id = parts[23]; } - if (id.StartsWith("folder_", StringComparison.OrdinalIgnoreCase)) + var enumNames = Enum.GetNames(typeof(StubType)); + foreach (var name in enumNames) { - stubType = StubType.Folder; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("people_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.People; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("latest_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Latest; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("playlists_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Playlists; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("Albums_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Albums; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("AlbumArtists_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.AlbumArtists; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("Artists_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Artists; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("Genres_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Genres; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("Songs_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.Songs; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("FavoriteAlbums_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.FavoriteAlbums; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("FavoriteArtists_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.FavoriteArtists; - id = id.Split(new[] { '_' }, 2)[1]; - } - else if (id.StartsWith("FavoriteSongs_", StringComparison.OrdinalIgnoreCase)) - { - stubType = StubType.FavoriteSongs; - id = id.Split(new[] { '_' }, 2)[1]; + if (id.StartsWith(name + "_", StringComparison.OrdinalIgnoreCase)) + { + stubType = (StubType)Enum.Parse(typeof(StubType), name, true); + id = id.Split(new[] { '_' }, 2)[1]; + + break; + } } if (Guid.TryParse(id, out itemId)) @@ -1048,6 +1341,14 @@ namespace Emby.Dlna.ContentDirectory Genres = 8, FavoriteSongs = 9, FavoriteArtists = 10, - FavoriteAlbums = 11 + FavoriteAlbums = 11, + ContinueWatching = 12, + Movies = 13, + Collections = 14, + Favorites = 15, + NextUp = 16, + Series = 17, + FavoriteSeries = 18, + FavoriteEpisodes = 19 } } diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index d2a160cf78..a1b692d98b 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -439,6 +439,38 @@ namespace Emby.Dlna.Didl { return _localization.GetLocalizedString("ViewTypeMusicFavoriteSongs"); } + if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching) + { + return _localization.GetLocalizedString("ViewTypeMovieResume"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.Movies) + { + return _localization.GetLocalizedString("ViewTypeMovieMovies"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.Collections) + { + return _localization.GetLocalizedString("ViewTypeMovieCollections"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites) + { + return _localization.GetLocalizedString("ViewTypeMovieFavorites"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp) + { + return _localization.GetLocalizedString("ViewTypeTvNextUp"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries) + { + return _localization.GetLocalizedString("ViewTypeTvFavoriteSeries"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes) + { + return _localization.GetLocalizedString("ViewTypeTvFavoriteEpisodes"); + } + if (itemStubType.HasValue && itemStubType.Value == StubType.Series) + { + return _localization.GetLocalizedString("ViewTypeTvShowSeries"); + } var episode = item as Episode; var season = context as Season; diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 67c9364374..8a239a2286 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -667,7 +667,7 @@ namespace Emby.Server.Core UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager); RegisterSingleInstance(UserViewManager); - var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory()); + var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager); RegisterSingleInstance(contentDirectory); var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory()); diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json index bc0dc236d4..133644ff7b 100644 --- a/Emby.Server.Implementations/Localization/Core/en-US.json +++ b/Emby.Server.Implementations/Localization/Core/en-US.json @@ -69,7 +69,7 @@ "ViewTypeTvResume": "Resume", "ViewTypeTvNextUp": "Next Up", "ViewTypeTvLatest": "Latest", - "ViewTypeTvShowSeries": "Series", + "ViewTypeTvShowSeries": "Shows", "ViewTypeTvGenres": "Genres", "ViewTypeTvFavoriteSeries": "Favorite Series", "ViewTypeTvFavoriteEpisodes": "Favorite Episodes", diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 1d74e87886..e4eb41e3a2 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.MediaEncoder var container = video.Container; - var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); + var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); _fileSystem.CopyFile(tempFile, path, true); try diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index c300fcce3e..4fde66d1ac 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Api.Playback LibraryManager = libraryManager; IsoManager = isoManager; MediaEncoder = mediaEncoder; - EncodingHelper = new EncodingHelper(MediaEncoder, serverConfig, FileSystem, SubtitleEncoder); + EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); } /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 6d2ec2eaba..4b3e340c99 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -19,14 +18,12 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IMediaEncoder _mediaEncoder; - private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly ISubtitleEncoder _subtitleEncoder; - public EncodingHelper(IMediaEncoder mediaEncoder, IServerConfigurationManager config, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) + public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) { _mediaEncoder = mediaEncoder; - _config = config; _fileSystem = fileSystem; _subtitleEncoder = subtitleEncoder; } @@ -1771,29 +1768,34 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } + return GetVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); + } + + public string GetVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) + { // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this. - if (state.VideoType != VideoType.VideoFile) + if (videoType != VideoType.VideoFile) { return null; } - if (state.VideoStream != null && - !string.IsNullOrWhiteSpace(state.VideoStream.Codec) && + if (videoStream != null && + !string.IsNullOrWhiteSpace(videoStream.Codec) && !string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType) && encodingOptions.EnableHardwareDecoding) { if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - switch (state.MediaSource.VideoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLower()) { case "avc": case "h264": if (_mediaEncoder.SupportsDecoder("h264_qsv")) { // qsv decoder does not support 10-bit input - if ((state.VideoStream.BitDepth ?? 8) > 8) + if ((videoStream.BitDepth ?? 8) > 8) { return null; } @@ -1824,7 +1826,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - switch (state.MediaSource.VideoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLower()) { case "avc": case "h264": diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 10d7b9a7e3..05bb35771e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -39,29 +39,16 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Extracts the video image. /// - /// The input files. - /// The protocol. - /// The threed format. - /// The offset. - /// The cancellation token. - /// Task{Stream}. - Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); - Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video images on interval. /// - /// The input files. - /// The protocol. - /// The threed format. - /// The interval. - /// The target directory. - /// The filename prefix. - /// The maximum width. - /// The cancellation token. - /// Task. Task ExtractVideoImagesOnInterval(string[] inputFiles, + string container, + MediaStream videoStream, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan interval, diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 3672e4e845..a291a98526 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -59,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder MediaSourceManager = mediaSourceManager; ProcessFactory = processFactory; - EncodingHelper = new EncodingHelper(MediaEncoder, ConfigurationManager, FileSystem, SubtitleEncoder); + EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); } public async Task Start(EncodingJobOptions options, diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f416ea4178..a2ebe08327 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -615,20 +615,20 @@ namespace MediaBrowser.MediaEncoding.Encoder public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(new[] { path }, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); + return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, container, null, protocol, false, threedFormat, offset, cancellationToken); + return ExtractImage(inputFiles, container, videoStream, null, protocol, false, threedFormat, offset, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, container, imageStreamIndex, protocol, false, null, null, cancellationToken); + return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, string container, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, + private async Task ExtractImage(string[] inputFiles, string container, MediaStream videoStream, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { var inputArgument = GetInputArgument(inputFiles, protocol); @@ -645,7 +645,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, true, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, cancellationToken).ConfigureAwait(false); } catch (ArgumentException) { @@ -657,10 +657,10 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, false, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, cancellationToken).ConfigureAwait(false); } - private async Task ExtractImageInternal(string inputPath, string container, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken) + private async Task ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -698,7 +698,7 @@ namespace MediaBrowser.MediaEncoding.Encoder break; } } - + var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; var enableThumbnail = !new List { "wtv" }.Contains(container ?? string.Empty, StringComparer.OrdinalIgnoreCase); @@ -726,6 +726,25 @@ namespace MediaBrowser.MediaEncoding.Encoder args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; } + var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder()); + if (videoStream != null) + { + var decoder = encodinghelper.GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions()); + if (!string.IsNullOrWhiteSpace(decoder)) + { + args = decoder + " " + args; + } + } + + if (!string.IsNullOrWhiteSpace(container)) + { + var inputFormat = encodinghelper.GetInputFormat(container); + if (!string.IsNullOrWhiteSpace(inputFormat)) + { + args = "-f " + inputFormat + " " + args; + } + } + var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, @@ -786,6 +805,8 @@ namespace MediaBrowser.MediaEncoding.Encoder } public async Task ExtractVideoImagesOnInterval(string[] inputFiles, + string container, + MediaStream videoStream, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan interval, @@ -825,6 +846,25 @@ namespace MediaBrowser.MediaEncoding.Encoder args = analyzeDurationArgument + " " + args; } + var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder()); + if (videoStream != null) + { + var decoder = encodinghelper.GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions()); + if (!string.IsNullOrWhiteSpace(decoder)) + { + args = decoder + " " + args; + } + } + + if (!string.IsNullOrWhiteSpace(container)) + { + var inputFormat = encodinghelper.GetInputFormat(container); + if (!string.IsNullOrWhiteSpace(inputFormat)) + { + args = "-f " + inputFormat + " " + args; + } + } + var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 08824913f8..a70e747747 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -164,7 +164,7 @@ namespace MediaBrowser.Model.Dto { foreach (MediaStream i in MediaStreams) { - if (i.Type == MediaStreamType.Video && StringHelper.IndexOfIgnoreCase(i.Codec ?? string.Empty, "jpeg") == -1) + if (i.Type == MediaStreamType.Video) { return i; } diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index ca701b70f6..bb1c4e6472 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoIndex, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, imageStream, videoIndex, cancellationToken).ConfigureAwait(false); } else { @@ -144,7 +144,9 @@ namespace MediaBrowser.Providers.MediaInfo ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1)) : TimeSpan.FromSeconds(10); - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); + var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); + + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); } return new DynamicImageResponse diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs index 035ac15c0b..f9ca238c7e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs @@ -60,10 +60,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers movie.SetProviderId(MetadataProviders.TmdbCollection, tmdbcolid); } - var val = reader.ReadElementContentAsString(); + var val = reader.ReadInnerXml(); + if (!string.IsNullOrWhiteSpace(val) && movie != null) { - movie.CollectionName = val; + // TODO Handle this better later + if (val.IndexOf('<') == -1) + { + movie.CollectionName = val; + } } break; diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index ff0973b0f2..a492f6b1d1 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.709 + 3.0.710 Emby.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 31b8ee0264..e130fbe4cf 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.709 + 3.0.710 Emby.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - + diff --git a/SharedVersion.cs b/SharedVersion.cs index c99800d242..d0e3bdd02e 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.26.11")] +[assembly: AssemblyVersion("3.2.26.12")]