diff options
46 files changed, 558 insertions, 253 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 08ac5671d..ed5fa5bfd 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -286,27 +286,65 @@ namespace MediaBrowser.Api job.DisposeKillTimer(); } - + public void OnTranscodeEndRequest(TranscodingJob job) { job.ActiveRequestCount--; if (job.ActiveRequestCount == 0) { - // TODO: Lower this hls timeout - var timerDuration = job.Type == TranscodingJobType.Progressive ? - 1000 : - 7200000; + PingTimer(job, true); + } + } + internal void PingTranscodingJob(string deviceId, string playSessionId) + { + if (string.IsNullOrEmpty(deviceId)) + { + throw new ArgumentNullException("deviceId"); + } - if (job.KillTimer == null) + var jobs = new List<TranscodingJob>(); + + lock (_activeTranscodingJobs) + { + // This is really only needed for HLS. + // Progressive streams can stop on their own reliably + jobs = jobs.Where(j => { - job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite); - } - else + if (string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase)) + { + return string.Equals(playSessionId, j.PlaySessionId, StringComparison.OrdinalIgnoreCase); + } + + return false; + + }).ToList(); + } + + foreach (var job in jobs) + { + PingTimer(job, false); + } + } + + private void PingTimer(TranscodingJob job, bool startTimerIfNeeded) + { + // TODO: Lower this hls timeout + var timerDuration = job.Type == TranscodingJobType.Progressive ? + 1000 : + 1800000; + + if (job.KillTimer == null) + { + if (startTimerIfNeeded) { - job.KillTimer.Change(timerDuration, Timeout.Infinite); + job.KillTimer = new Timer(OnTranscodeKillTimerStopped, job, timerDuration, Timeout.Infinite); } } + else + { + job.KillTimer.Change(timerDuration, Timeout.Infinite); + } } /// <summary> diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index d0abd18c2..9f6c07dd2 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -123,7 +123,7 @@ namespace MediaBrowser.Api public void Post(AutoSetMetadataOptions request) { - _configurationManager.DisableMetadataService("Media Browser Xml"); + _configurationManager.DisableMetadataService("Emby Xml"); _configurationManager.SaveConfiguration(); } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 24c91e172..bb6f74f36 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -186,6 +186,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { get; set; } + [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? StartIndex { get; set; } @@ -218,6 +221,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? HasAired { get; set; } + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsSports { get; set; } + [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMovie { get; set; } } @@ -422,6 +428,7 @@ namespace MediaBrowser.Api.LiveTv query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortOrder = request.SortOrder; query.IsMovie = request.IsMovie; + query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false); @@ -437,7 +444,8 @@ namespace MediaBrowser.Api.LiveTv IsAiring = request.IsAiring, Limit = request.Limit, HasAired = request.HasAired, - IsMovie = request.IsMovie + IsMovie = request.IsMovie, + IsSports = request.IsSports }; var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs index ba3f17257..0692c4863 100644 --- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; @@ -518,25 +517,14 @@ namespace MediaBrowser.Api.Playback.Dash private async Task WaitForSegment(string playlist, string segment, CancellationToken cancellationToken) { - var tmpPath = playlist + ".tmp"; - var segmentFilename = Path.GetFileName(segment); Logger.Debug("Waiting for {0} in {1}", segmentFilename, playlist); while (true) { - FileStream fileStream; - try - { - fileStream = FileSystem.GetFileStream(tmpPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); - } - catch (IOException) - { - fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); - } // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written - using (fileStream) + using (var fileStream = GetPlaylistFileStream(playlist)) { using (var reader = new StreamReader(fileStream)) { diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 207bc2f67..701516b48 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; @@ -186,7 +185,7 @@ namespace MediaBrowser.Api.Playback.Hls while (true) { // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written - using (var fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) + using (var fileStream = GetPlaylistFileStream(playlist)) { using (var reader = new StreamReader(fileStream)) { @@ -212,6 +211,20 @@ namespace MediaBrowser.Api.Playback.Hls } } + protected Stream GetPlaylistFileStream(string path) + { + var tmpPath = path + ".tmp"; + + try + { + return FileSystem.GetFileStream(tmpPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); + } + catch (IOException) + { + return FileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); + } + } + protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding) { var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index cbfadb886..98d6c9a76 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; @@ -300,7 +299,7 @@ namespace MediaBrowser.Api.Playback.Hls var segmentFilename = Path.GetFileName(segmentPath); - using (var fileStream = FileSystem.GetFileStream(playlistPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) + using (var fileStream = GetPlaylistFileStream(playlistPath)) { using (var reader = new StreamReader(fileStream)) { diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs index 58cfa086e..ff79bb48f 100644 --- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs +++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback var options = GetOptions(); - if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) + if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) { PauseTranscoding(); } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 609c1048f..b2364ce3c 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -142,7 +142,7 @@ namespace MediaBrowser.Api.UserLibrary } IEnumerable<Tuple<TItemType, List<BaseItem>>> tuples; - if (dtoOptions.Fields.Contains(ItemFields.ItemCounts) || true) + if (dtoOptions.Fields.Contains(ItemFields.ItemCounts)) { tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList())); } @@ -177,7 +177,6 @@ namespace MediaBrowser.Api.UserLibrary return true; } - return true; return options.Fields.Contains(ItemFields.ItemCounts); } diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index 55e1681e0..6c767596e 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -294,6 +294,11 @@ namespace MediaBrowser.Api.UserLibrary public void Post(ReportPlaybackProgress request) { + if (!string.IsNullOrWhiteSpace(request.PlaySessionId)) + { + ApiEntryPoint.Instance.PingTranscodingJob(AuthorizationContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId); + } + request.SessionId = GetSession().Result.Id; var task = _sessionManager.OnPlaybackProgress(request); @@ -317,6 +322,11 @@ namespace MediaBrowser.Api.UserLibrary public void Post(ReportPlaybackStopped request) { + if (!string.IsNullOrWhiteSpace(request.PlaySessionId)) + { + ApiEntryPoint.Instance.KillTranscodingJobs(AuthorizationContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); + } + request.SessionId = GetSession().Result.Id; var task = _sessionManager.OnPlaybackStopped(request); diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index b6514ca0a..f746d87ff 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -15,19 +14,9 @@ namespace MediaBrowser.Controller.Channels public override bool IsVisible(User user) { - if (user.Policy.BlockedChannels != null) + if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { - if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } - } - else - { - if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } + return false; } return base.IsVisible(user); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cdb52ec66..94fc76125 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1219,18 +1219,6 @@ namespace MediaBrowser.Controller.Entities private BaseItem FindLinkedChild(LinkedChild info) { - if (!string.IsNullOrWhiteSpace(info.ItemName)) - { - if (string.Equals(info.ItemType, "musicgenre", StringComparison.OrdinalIgnoreCase)) - { - return LibraryManager.GetMusicGenre(info.ItemName); - } - if (string.Equals(info.ItemType, "musicartist", StringComparison.OrdinalIgnoreCase)) - { - return LibraryManager.GetArtist(info.ItemName); - } - } - if (!string.IsNullOrEmpty(info.Path)) { var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); @@ -1243,23 +1231,6 @@ namespace MediaBrowser.Controller.Entities return itemByPath; } - if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) - { - return LibraryManager.RootFolder.GetRecursiveChildren(i => - { - if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - - }).FirstOrDefault(); - } - return null; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index cffc0989a..14095f7ff 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -334,22 +334,9 @@ namespace MediaBrowser.Controller.Entities { if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.Policy.BlockedMediaFolders != null) + if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { - if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || - - // Backwards compatibility - user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) - { - return false; - } - } - else - { - if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } + return false; } } diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 949c9741b..ac13657b9 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -9,9 +9,6 @@ namespace MediaBrowser.Controller.Entities public string Path { get; set; } public LinkedChildType Type { get; set; } - public string ItemName { get; set; } - public string ItemType { get; set; } - [IgnoreDataMember] public string Id { get; set; } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 9cbbabc8d..5bcc5f313 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -63,15 +63,7 @@ namespace MediaBrowser.Controller.Library /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param> /// <param name="user">The user.</param> /// <returns>IEnumerable<MediaSourceInfo>.</returns> - IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user); - - /// <summary> - /// Gets the static media sources. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param> - /// <returns>IEnumerable<MediaSourceInfo>.</returns> - IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution); + IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null); /// <summary> /// Gets the static media source. diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 6facc1074..13f83c0fc 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -1404,24 +1404,12 @@ namespace MediaBrowser.Controller.Providers { switch (reader.Name) { - case "Name": - { - linkedItem.ItemName = reader.ReadElementContentAsString(); - break; - } - case "Path": { linkedItem.Path = reader.ReadElementContentAsString(); break; } - case "Type": - { - linkedItem.ItemType = reader.ReadElementContentAsString(); - break; - } - default: reader.Skip(); break; @@ -1435,7 +1423,7 @@ namespace MediaBrowser.Controller.Providers return linkedItem; } - return string.IsNullOrWhiteSpace(linkedItem.ItemName) || string.IsNullOrWhiteSpace(linkedItem.ItemType) ? null : linkedItem; + return null; } diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 3b1cdb542..19dab2246 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -124,7 +124,7 @@ namespace MediaBrowser.Dlna.Didl { if (streamInfo == null) { - var sources = _user == null ? _mediaSourceManager.GetStaticMediaSources(video, true).ToList() : _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList(); + var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList(); streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions { @@ -351,7 +351,7 @@ namespace MediaBrowser.Dlna.Didl if (streamInfo == null) { - var sources = _user == null ? _mediaSourceManager.GetStaticMediaSources(audio, true).ToList() : _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList(); + var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList(); streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions { diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index 38c0f71cc..5b129243c 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -470,7 +470,7 @@ namespace MediaBrowser.Dlna.PlayTo var hasMediaSources = item as IHasMediaSources; var mediaSources = hasMediaSources != null - ? (user == null ? _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true) : _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList() + ? (_mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList() : new List<MediaSourceInfo>(); var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex); diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index afe4b5799..154d02600 100644 --- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs @@ -92,7 +92,7 @@ namespace MediaBrowser.LocalMetadata { get { - return "Media Browser Xml"; + return "Emby Xml"; } } diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs index c59d574bf..1b98e75be 100644 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -756,11 +756,6 @@ namespace MediaBrowser.LocalMetadata.Savers { builder.Append("<" + singularNodeName + ">"); - if (!string.IsNullOrWhiteSpace(link.ItemType)) - { - builder.Append("<Type>" + SecurityElement.Escape(link.ItemType) + "</Type>"); - } - if (!string.IsNullOrWhiteSpace(link.Path)) { builder.Append("<Path>" + SecurityElement.Escape((link.Path)) + "</Path>"); diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c06aedb50..bc167333a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -200,7 +200,7 @@ namespace MediaBrowser.Model.Configuration public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } - public string[] InsecureApps8 { get; set; } + public string[] InsecureApps9 { get; set; } public bool SaveMetadataHidden { get; set; } @@ -257,7 +257,7 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); - InsecureApps8 = new[] + InsecureApps9 = new[] { "Chromecast", "iOS", @@ -266,7 +266,6 @@ namespace MediaBrowser.Model.Configuration "Media Portal", "iPad", "iPhone", - "Roku", "Windows Phone" }; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 7390af088..9cd8c1067 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -7,12 +7,6 @@ namespace MediaBrowser.Model.Configuration public class UserConfiguration { /// <summary> - /// Gets or sets a value indicating whether this instance is administrator. - /// </summary> - /// <value><c>true</c> if this instance is administrator; otherwise, <c>false</c>.</value> - public bool IsAdministrator { get; set; } - - /// <summary> /// Gets or sets the audio language preference. /// </summary> /// <value>The audio language preference.</value> @@ -53,7 +47,6 @@ namespace MediaBrowser.Model.Configuration public string[] LatestItemsExcludes { get; set; } - public bool HasMigratedToPolicy { get; set; } public bool HidePlayedInLatest { get; set; } /// <summary> diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index bbd396c33..c19ba54bd 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -54,6 +54,12 @@ namespace MediaBrowser.Model.LiveTv public bool? IsMovie { get; set; } /// <summary> + /// Gets or sets a value indicating whether this instance is sports. + /// </summary> + /// <value><c>null</c> if [is sports] contains no value, <c>true</c> if [is sports]; otherwise, <c>false</c>.</value> + public bool? IsSports { get; set; } + + /// <summary> /// Skips over a given number of items within the results. Use for paging. /// </summary> public int? StartIndex { get; set; } diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 9ba8e0e5f..4a8ae2365 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -31,5 +31,10 @@ /// </summary> /// <value><c>null</c> if [is movie] contains no value, <c>true</c> if [is movie]; otherwise, <c>false</c>.</value> public bool? IsMovie { get; set; } + /// <summary> + /// Gets or sets a value indicating whether this instance is sports. + /// </summary> + /// <value><c>null</c> if [is sports] contains no value, <c>true</c> if [is sports]; otherwise, <c>false</c>.</value> + public bool? IsSports { get; set; } } }
\ No newline at end of file diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs index e57955c9e..683f1a76c 100644 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Users; namespace MediaBrowser.Model.Notifications { @@ -106,7 +107,7 @@ namespace MediaBrowser.Model.Notifications !ListHelper.ContainsIgnoreCase(opt.DisabledMonitorUsers, userId); } - public bool IsEnabledToSendToUser(string type, string userId, UserConfiguration userConfig) + public bool IsEnabledToSendToUser(string type, string userId, UserPolicy userPolicy) { NotificationOption opt = GetOptions(type); @@ -117,7 +118,7 @@ namespace MediaBrowser.Model.Notifications return true; } - if (opt.SendToUserMode == SendToUserType.Admins && userConfig.IsAdministrator) + if (opt.SendToUserMode == SendToUserType.Admins && userPolicy.IsAdministrator) { return true; } diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index 0cdf5ca7a..5a88c0d43 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -281,6 +281,13 @@ namespace MediaBrowser.Model.Querying public int? ImageTypeLimit { get; set; } public ImageType[] EnableImageTypes { get; set; } + [Obsolete] + public string[] Artists { get; set; } + [Obsolete] + public string[] Studios { get; set; } + [Obsolete] + public string Person { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="ItemQuery" /> class. /// </summary> @@ -299,6 +306,9 @@ namespace MediaBrowser.Model.Querying VideoTypes = new VideoType[] { }; + Artists = new string[] { }; + Studios = new string[] { }; + Genres = new string[] { }; StudioIds = new string[] { }; IncludeItemTypes = new string[] { }; diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs index fcc7e39a1..9c2926b54 100644 --- a/MediaBrowser.Model/Querying/ItemSortBy.cs +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -43,6 +43,7 @@ namespace MediaBrowser.Model.Querying /// The premiere date /// </summary> public const string PremiereDate = "PremiereDate"; + public const string StartDate = "StartDate"; /// <summary> /// The sort name /// </summary> diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 774d4a0b4..640f03e2a 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -32,8 +32,6 @@ namespace MediaBrowser.Model.Users public bool EnableUserPreferenceAccess { get; set; } public AccessSchedule[] AccessSchedules { get; set; } public UnratedItem[] BlockUnratedItems { get; set; } - public string[] BlockedMediaFolders { get; set; } - public string[] BlockedChannels { get; set; } public bool EnableRemoteControlOfOtherUsers { get; set; } public bool EnableSharedDeviceControl { get; set; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index 3903c62b1..b4da40702 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security return true; } - return _config.Configuration.InsecureApps8.Contains(auth.Client ?? string.Empty, + return _config.Configuration.InsecureApps9.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs b/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs index 4bde30dac..1c01fa9e0 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ThrottledStream.cs @@ -15,8 +15,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// </summary> public const long Infinite = 0; - public Func<long, long, long> ThrottleCallback { get; set; } - #region Private members /// <summary> /// The base stream. @@ -293,16 +291,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer return false; } - if (ThrottleCallback != null) - { - var val = ThrottleCallback(_maximumBytesPerSecond, _bytesWritten); - - if (val == 0) - { - return false; - } - } - return true; } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 4fab95263..27a7d4ea9 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -235,7 +235,7 @@ namespace MediaBrowser.Server.Implementations.Library return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); } - public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution) + public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null) { if (item == null) { @@ -247,31 +247,14 @@ namespace MediaBrowser.Server.Implementations.Library return item.GetMediaSources(enablePathSubstitution); } - return item.GetMediaSources(enablePathSubstitution); - } - - public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user) - { - if (item == null) - { - throw new ArgumentNullException("item"); - } - - if (!(item is Video)) - { - return item.GetMediaSources(enablePathSubstitution); - } - - if (user == null) - { - throw new ArgumentNullException("user"); - } - var sources = item.GetMediaSources(enablePathSubstitution).ToList(); - foreach (var source in sources) + if (user != null) { - SetUserProperties(source, user); + foreach (var source in sources) + { + SetUserProperties(source, user); + } } return sources; diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index b101f6ae1..03471a8e9 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -166,11 +166,6 @@ namespace MediaBrowser.Server.Implementations.Library var users = Users.ToList(); - foreach (var user in users) - { - await DoPolicyMigration(user).ConfigureAwait(false); - } - // If there are no local users with admin rights, make them all admins if (!users.Any(i => i.Policy.IsAdministrator)) { @@ -286,10 +281,10 @@ namespace MediaBrowser.Server.Implementations.Library if (newValue >= maxCount) { - //_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); - //user.Policy.IsDisabled = true; + _logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); + user.Policy.IsDisabled = true; - //fireLockout = true; + fireLockout = true; } await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); @@ -366,19 +361,6 @@ namespace MediaBrowser.Server.Implementations.Library return users; } - private async Task DoPolicyMigration(User user) - { - if (!user.Configuration.HasMigratedToPolicy) - { - user.Policy.IsAdministrator = user.Configuration.IsAdministrator; - - await UpdateUserPolicy(user, user.Policy, false); - - user.Configuration.HasMigratedToPolicy = true; - await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); - } - } - public UserDto GetUserDto(User user, string remoteEndPoint = null) { if (user == null) @@ -953,8 +935,6 @@ namespace MediaBrowser.Server.Implementations.Library user.Policy = userPolicy; } - user.Configuration.IsAdministrator = user.Policy.IsAdministrator; - await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index a39781d6a..cb9bb7711 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -761,6 +761,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(p => p.IsMovie == query.IsMovie); } + if (query.IsSports.HasValue) + { + programs = programs.Where(p => p.IsSports == query.IsSports); + } + programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending) .Cast<LiveTvProgram>(); @@ -826,6 +831,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(p => p.IsMovie == query.IsMovie.Value); } + if (query.IsSports.HasValue) + { + programs = programs.Where(p => p.IsSports == query.IsSports.Value); + } + var programList = programs.ToList(); var genres = programList.SelectMany(i => i.Genres) @@ -996,6 +1006,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(90 + (p * .1))); await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false); + + foreach (var program in _programs.Values + .Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1) + .ToList()) + { + RefreshIfNeeded(program); + } } finally { diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index ae20fafba..9c53eb92e 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -35,8 +35,11 @@ "HeaderConfirmation": "Confirmation", "MessageKeyUpdated": "Thank you. Your supporter key has been updated.", "MessageKeyRemoved": "Thank you. Your supporter key has been removed.", + "HeaderSupportTheTeam": "Support the Emby Team", + "TextEnjoyBonusFeatures": "Enjoy Bonus Features", "TitleLiveTV": "Live TV", "TitleSync": "Sync", + "ButtonDonate": "Donate", "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.", "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.", "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Emby Connect members to enjoy free access to the following apps:", @@ -175,6 +178,9 @@ "OptionThursday": "Thursday", "OptionFriday": "Friday", "OptionSaturday": "Saturday", + "OptionEveryday": "Every day", + "OptionWeekend": "Weekends", + "OptionWeekday": "Weekdays", "HeaderConfirmDeletion": "Confirm Deletion", "MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?", "LiveTvUpdateAvailable": "(Update available)", diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 0cff99c5d..835e9b3be 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -168,6 +168,7 @@ "MessageNothingHere": "Nothing here.", "MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.", "TabSuggested": "Suggested", + "TabSuggestions": "Suggestions", "TabLatest": "Latest", "TabUpcoming": "Upcoming", "TabShows": "Shows", @@ -912,8 +913,8 @@ "OptionDefaultSort": "Default", "OptionCommunityMostWatchedSort": "Most Watched", "TabNextUp": "Next Up", + "PlaceholderUsername": "Username", "HeaderBecomeProjectSupporter": "Become an Emby Supporter", - "TextEnjoyBonusFeatures": "Enjoy Bonus Features", "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.", "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.", "MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.", @@ -1398,6 +1399,7 @@ "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:", "OptionTVMovies": "TV Movies", "HeaderUpcomingMovies": "Upcoming Movies", + "HeaderUpcomingSports": "Upcoming Sports", "HeaderUpcomingPrograms": "Upcoming Programs", "ButtonMoreItems": "More...", "LabelShowLibraryTileNames": "Show library tile names", diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index db2397d2f..dd770b0c8 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -233,6 +233,7 @@ <Compile Include="Localization\LocalizationManager.cs" /> <Compile Include="Logging\PatternsLogger.cs" /> <Compile Include="MediaEncoder\EncodingManager.cs" /> + <Compile Include="Sorting\StartDateComparer.cs" /> <Compile Include="Sync\SyncHelper.cs" /> <Compile Include="Sync\SyncJobOptions.cs" /> <Compile Include="UserViews\DynamicImageProvider.cs" /> diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 5e02b2bac..1ff928cd5 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Notifications var config = GetConfiguration(); return _userManager.Users - .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) + .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Policy)) .Select(i => i.Id.ToString("N")); } diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs index 1063fde53..79a1181ca 100644 --- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs @@ -3,12 +3,13 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; +using MediaBrowser.Server.Implementations.UserViews; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Threading; @@ -125,7 +126,7 @@ namespace MediaBrowser.Server.Implementations.Photos protected abstract Task<List<BaseItem>> GetItemsWithImages(IHasImages item); - private const string Version = "5"; + private const string Version = "18"; protected string GetConfigurationCacheKey(List<BaseItem> items, string itemName) { var parts = Version + "_" + (itemName ?? string.Empty) + "_" + @@ -134,30 +135,32 @@ namespace MediaBrowser.Server.Implementations.Photos return parts.GetMD5().ToString("N"); } - protected Task<Stream> GetThumbCollage(List<BaseItem> items) + protected Task<Stream> GetThumbCollage(IHasImages primaryItem, List<BaseItem> items) { - var files = items - .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb)) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .ToList(); + var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(items), 960, 540, true, primaryItem.Name); - return DynamicImageHelpers.GetThumbCollage(files, - FileSystem, - 1600, - 900, - ApplicationPaths); + return Task.FromResult(stream); } - protected Task<Stream> GetSquareCollage(List<BaseItem> items) + private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items) { - var files = items + return items .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb)) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .ToList(); + .Where(i => !string.IsNullOrWhiteSpace(i)); + } - return DynamicImageHelpers.GetSquareCollage(files, - FileSystem, - 800, ApplicationPaths); + protected Task<Stream> GetPosterCollage(IHasImages primaryItem, List<BaseItem> items) + { + var stream = new StripCollageBuilder(ApplicationPaths).BuildPosterCollage(GetStripCollageImagePaths(items), 600, 900, true, primaryItem.Name); + + return Task.FromResult(stream); + } + + protected Task<Stream> GetSquareCollage(IHasImages primaryItem, List<BaseItem> items) + { + var stream = new StripCollageBuilder(ApplicationPaths).BuildSquareCollage(GetStripCollageImagePaths(items), 800, 800, true, primaryItem.Name); + + return Task.FromResult(stream); } public string Name @@ -175,9 +178,19 @@ namespace MediaBrowser.Server.Implementations.Photos return null; } - return imageType == ImageType.Thumb ? - await GetThumbCollage(itemsWithImages).ConfigureAwait(false) : - await GetSquareCollage(itemsWithImages).ConfigureAwait(false); + if (imageType == ImageType.Thumb) + { + return await GetThumbCollage(item, itemsWithImages).ConfigureAwait(false); + } + + if (imageType == ImageType.Primary) + { + return item is PhotoAlbum || item is Playlist ? + await GetSquareCollage(item, itemsWithImages).ConfigureAwait(false) : + await GetPosterCollage(item, itemsWithImages).ConfigureAwait(false); + } + + throw new ArgumentException("Unexpected image type"); } public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) diff --git a/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs b/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs new file mode 100644 index 000000000..7e6f24ec1 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/StartDateComparer.cs @@ -0,0 +1,47 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Querying; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class StartDateComparer : IBaseItemComparer + { + /// <summary> + /// Compares the specified x. + /// </summary> + /// <param name="x">The x.</param> + /// <param name="y">The y.</param> + /// <returns>System.Int32.</returns> + public int Compare(BaseItem x, BaseItem y) + { + return GetDate(x).CompareTo(GetDate(y)); + } + + /// <summary> + /// Gets the date. + /// </summary> + /// <param name="x">The x.</param> + /// <returns>DateTime.</returns> + private DateTime GetDate(BaseItem x) + { + var hasStartDate = x as LiveTvProgram; + + if (hasStartDate != null) + { + return hasStartDate.StartDate; + } + return DateTime.MinValue; + } + + /// <summary> + /// Gets the name. + /// </summary> + /// <value>The name.</value> + public string Name + { + get { return ItemSortBy.StartDate; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs index d6a94210c..7bcbbd6a8 100644 --- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -107,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.UserViews User = _userManager.GetUserById(view.UserId.Value), CollapseBoxSetItems = false, Recursive = recursive, - ExcludeItemTypes = new[] { "UserView", "CollectionFolder" } + ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" } }).ConfigureAwait(false); @@ -248,8 +248,7 @@ namespace MediaBrowser.Server.Implementations.UserViews return null; } - var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages, view.ViewType), item.Name, 960, 540); - return stream; + return new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages, view.ViewType), 960, 540, false, item.Name); } return await base.CreateImageAsync(item, itemsWithImages, imageType, imageIndex); diff --git a/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs b/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs index 0bf4d8e4a..a9ac0946a 100644 --- a/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs +++ b/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs @@ -18,8 +18,45 @@ namespace MediaBrowser.Server.Implementations.UserViews _appPaths = appPaths; } - public Stream BuildThumbCollage(IEnumerable<string> paths, string text, int width, int height) + public Stream BuildPosterCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text) { + if (renderWithText) + { + using (var wand = BuildPosterCollageWandWithText(paths, text, width, height)) + { + return DynamicImageHelpers.GetStream(wand, _appPaths); + } + } + using (var wand = BuildPosterCollageWand(paths, width, height)) + { + return DynamicImageHelpers.GetStream(wand, _appPaths); + } + } + + public Stream BuildSquareCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text) + { + if (renderWithText) + { + using (var wand = BuildSquareCollageWandWithText(paths, text, width, height)) + { + return DynamicImageHelpers.GetStream(wand, _appPaths); + } + } + using (var wand = BuildSquareCollageWand(paths, width, height)) + { + return DynamicImageHelpers.GetStream(wand, _appPaths); + } + } + + public Stream BuildThumbCollage(IEnumerable<string> paths, int width, int height, bool renderWithText, string text) + { + if (renderWithText) + { + using (var wand = BuildThumbCollageWandWithText(paths, text, width, height)) + { + return DynamicImageHelpers.GetStream(wand, _appPaths); + } + } using (var wand = BuildThumbCollageWand(paths, width, height)) { return DynamicImageHelpers.GetStream(wand, _appPaths); @@ -60,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.UserViews { draw.FillColor = fcolor; draw.Font = MontserratLightFont; - draw.FontSize = 50; + draw.FontSize = 60; draw.FontWeight = FontWeightType.LightStyle; draw.TextAntialias = true; } @@ -116,6 +153,131 @@ namespace MediaBrowser.Server.Implementations.UserViews } } + private MagickWand BuildPosterCollageWand(IEnumerable<string> paths, int width, int height) + { + var inputPaths = ProjectPaths(paths, 4); + using (var wandImages = new MagickWand(inputPaths)) + { + var wand = new MagickWand(width, height); + wand.OpenImage("gradient:#111111-#111111"); + using (var draw = new DrawingWand()) + { + var iSlice = Convert.ToInt32(width * 0.225); + int iTrans = Convert.ToInt32(height * .25); + int iHeight = Convert.ToInt32(height * .65); + var horizontalImagePadding = Convert.ToInt32(width * 0.0275); + + foreach (var element in wandImages.ImageList) + { + int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height); + element.Gravity = GravityType.CenterGravity; + element.BackgroundColor = ColorName.Black; + element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter); + int ix = (int)Math.Abs((iWidth - iSlice) / 2); + element.CropImage(iSlice, iHeight, ix, 0); + + element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0); + } + + wandImages.SetFirstIterator(); + using (var wandList = wandImages.AppendImages()) + { + wandList.CurrentImage.TrimImage(1); + using (var mwr = wandList.CloneMagickWand()) + { + mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1); + mwr.CurrentImage.FlipImage(); + + mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel; + mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70); + + using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans)) + { + mwg.OpenImage("gradient:black-none"); + var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); + mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing); + + wandList.AddImage(mwr); + int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2; + wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .05)); + } + } + } + } + + return wand; + } + } + + private MagickWand BuildPosterCollageWandWithText(IEnumerable<string> paths, string label, int width, int height) + { + var inputPaths = ProjectPaths(paths, 4); + using (var wandImages = new MagickWand(inputPaths)) + { + var wand = new MagickWand(width, height); + wand.OpenImage("gradient:#111111-#111111"); + using (var draw = new DrawingWand()) + { + using (var fcolor = new PixelWand(ColorName.White)) + { + draw.FillColor = fcolor; + draw.Font = MontserratLightFont; + draw.FontSize = 60; + draw.FontWeight = FontWeightType.LightStyle; + draw.TextAntialias = true; + } + + var fontMetrics = wand.QueryFontMetrics(draw, label); + var textContainerY = Convert.ToInt32(height * .165); + wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label); + + var iSlice = Convert.ToInt32(width * 0.225); + int iTrans = Convert.ToInt32(height * 0.2); + int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296); + var horizontalImagePadding = Convert.ToInt32(width * 0.0275); + + foreach (var element in wandImages.ImageList) + { + int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height); + element.Gravity = GravityType.CenterGravity; + element.BackgroundColor = new PixelWand("none", 1); + element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter); + int ix = (int)Math.Abs((iWidth - iSlice) / 2); + element.CropImage(iSlice, iHeight, ix, 0); + + element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0); + } + + wandImages.SetFirstIterator(); + using (var wandList = wandImages.AppendImages()) + { + wandList.CurrentImage.TrimImage(1); + using (var mwr = wandList.CloneMagickWand()) + { + mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1); + mwr.CurrentImage.FlipImage(); + + mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel; + mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60); + + using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans)) + { + mwg.OpenImage("gradient:black-none"); + var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); + mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing); + + wandList.AddImage(mwr); + int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2; + wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852)); + } + } + } + } + + return wand; + } + } + private MagickWand BuildThumbCollageWand(IEnumerable<string> paths, int width, int height) { var inputPaths = ProjectPaths(paths, 8); @@ -172,6 +334,131 @@ namespace MediaBrowser.Server.Implementations.UserViews } } + private MagickWand BuildSquareCollageWand(IEnumerable<string> paths, int width, int height) + { + var inputPaths = ProjectPaths(paths, 4); + using (var wandImages = new MagickWand(inputPaths)) + { + var wand = new MagickWand(width, height); + wand.OpenImage("gradient:#111111-#111111"); + using (var draw = new DrawingWand()) + { + var iSlice = Convert.ToInt32(width * .225); + int iTrans = Convert.ToInt32(height * .25); + int iHeight = Convert.ToInt32(height * .63); + var horizontalImagePadding = Convert.ToInt32(width * 0.02); + + foreach (var element in wandImages.ImageList) + { + int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height); + element.Gravity = GravityType.CenterGravity; + element.BackgroundColor = ColorName.Black; + element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter); + int ix = (int)Math.Abs((iWidth - iSlice) / 2); + element.CropImage(iSlice, iHeight, ix, 0); + + element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0); + } + + wandImages.SetFirstIterator(); + using (var wandList = wandImages.AppendImages()) + { + wandList.CurrentImage.TrimImage(1); + using (var mwr = wandList.CloneMagickWand()) + { + mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1); + mwr.CurrentImage.FlipImage(); + + mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel; + mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70); + + using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans)) + { + mwg.OpenImage("gradient:black-none"); + var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); + mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing); + + wandList.AddImage(mwr); + int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2; + wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .07)); + } + } + } + } + + return wand; + } + } + + private MagickWand BuildSquareCollageWandWithText(IEnumerable<string> paths, string label, int width, int height) + { + var inputPaths = ProjectPaths(paths, 4); + using (var wandImages = new MagickWand(inputPaths)) + { + var wand = new MagickWand(width, height); + wand.OpenImage("gradient:#111111-#111111"); + using (var draw = new DrawingWand()) + { + using (var fcolor = new PixelWand(ColorName.White)) + { + draw.FillColor = fcolor; + draw.Font = MontserratLightFont; + draw.FontSize = 60; + draw.FontWeight = FontWeightType.LightStyle; + draw.TextAntialias = true; + } + + var fontMetrics = wand.QueryFontMetrics(draw, label); + var textContainerY = Convert.ToInt32(height * .165); + wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, label); + + var iSlice = Convert.ToInt32(width * .225); + int iTrans = Convert.ToInt32(height * 0.2); + int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296); + var horizontalImagePadding = Convert.ToInt32(width * 0.02); + + foreach (var element in wandImages.ImageList) + { + int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height); + element.Gravity = GravityType.CenterGravity; + element.BackgroundColor = new PixelWand("none", 1); + element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter); + int ix = (int)Math.Abs((iWidth - iSlice) / 2); + element.CropImage(iSlice, iHeight, ix, 0); + + element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0); + } + + wandImages.SetFirstIterator(); + using (var wandList = wandImages.AppendImages()) + { + wandList.CurrentImage.TrimImage(1); + using (var mwr = wandList.CloneMagickWand()) + { + mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1); + mwr.CurrentImage.FlipImage(); + + mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel; + mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60); + + using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans)) + { + mwg.OpenImage("gradient:black-none"); + var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); + mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing); + + wandList.AddImage(mwr); + int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2; + wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852)); + } + } + } + } + + return wand; + } + } + private string MontserratLightFont { get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths); } diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs index cabb8dc83..4d2ed067b 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg var info = new FFMpegDownloadInfo(); // Windows builds: http://ffmpeg.zeranoe.com/builds/ - // Linux builds: http://ffmpeg.gusari.org/static/ + // Linux builds: http://johnvansickle.com/ffmpeg/ // OS X builds: http://ffmpegmac.net/ // OS X x64: http://www.evermeet.cx/ffmpeg/ @@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case OperatingSystem.Linux: info.ArchiveType = "7z"; - info.Version = "20150124"; + info.Version = "20150331"; break; case OperatingSystem.Osx: @@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg info.FFMpegFilename = "ffmpeg.exe"; info.FFProbeFilename = "ffprobe.exe"; - info.Version = "20150110"; + info.Version = "20150331"; info.ArchiveType = "7z"; switch (environment.SystemArchitecture) @@ -83,14 +83,14 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case Architecture.X86_X64: return new[] { - "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150110-git-4df01d5-win64-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150110-git-4df01d5-win64-static.7z" + "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150331-git-5cba529-win64-static.7z", + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150331-git-5cba529-win64-static.7z" }; case Architecture.X86: return new[] { - "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150110-git-4df01d5-win32-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150110-git-4df01d5-win32-static.7z" + "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150331-git-5cba529-win32-static.7z", + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150331-git-5cba529-win32-static.7z" }; } break; @@ -119,12 +119,12 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case Architecture.X86_X64: return new[] { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.5.3-64bit-static.7z" + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.6.1-64bit-static.7z" }; case Architecture.X86: return new[] { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.5.3-32bit-static.7z" + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.6.1-32bit-static.7z" }; } break; diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs index d4cefdb10..fe7cd943a 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloader.cs @@ -202,7 +202,14 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg } } - throw new ApplicationException("Unable to download required components. Please try again later."); + if (downloadinfo.DownloadUrls.Length == 0) + { + throw new ApplicationException("ffmpeg unvailable. Please install it and start the server with two command line arguments: -ffmpeg \"{PATH}\" and -ffprobe \"{PATH}\""); + } + else + { + throw new ApplicationException("Unable to download required components. Please try again later."); + } } private void ExtractFFMpeg(FFMpegDownloadInfo downloadinfo, string tempFile, string targetFolder) diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs index be8ae2f81..49114b96f 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs @@ -44,7 +44,12 @@ namespace MediaBrowser.Server.Startup.Common.Migrations { if (string.Equals(options[i], "Media Browser Legacy Xml", StringComparison.OrdinalIgnoreCase)) { - options[i] = "Media Browser Xml"; + options[i] = "Emby Xml"; + changed = true; + } + else if (string.Equals(options[i], "Media Browser Xml", StringComparison.OrdinalIgnoreCase)) + { + options[i] = "Emby Xml"; changed = true; } } diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 8982b5739..5138b157f 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -451,7 +451,6 @@ namespace MediaBrowser.WebDashboard.Api "moviegenres.js", "moviecollections.js", "movies.js", - "movieslatest.js", "moviepeople.js", "moviesrecommended.js", "moviestudios.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 2725d63ad..88a2a8ae1 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -556,9 +556,6 @@ <Content Include="dashboard-ui\metadatasubtitles.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\movieslatest.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\musicalbumartists.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -889,9 +886,6 @@ <Content Include="dashboard-ui\scripts\metadatasubtitles.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\movieslatest.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\musicalbumartists.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 5c4319d22..9cde958c4 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -856,16 +856,6 @@ namespace MediaBrowser.XbmcMetadata.Savers { writer.WriteStartElement("collectionitem"); - if (!string.IsNullOrWhiteSpace(link.ItemName)) - { - writer.WriteElementString("name", link.ItemName); - } - - if (!string.IsNullOrWhiteSpace(link.ItemType)) - { - writer.WriteElementString("type", link.ItemType); - } - if (!string.IsNullOrWhiteSpace(link.Path)) { writer.WriteElementString("path", link.Path); |
