From b5218034acb3149b6b5db658120611ba1469d8bb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 18 Apr 2015 02:15:31 -0400 Subject: add tuner url --- MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs index cdf2f0ef52..46cf4dd98c 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.LiveTv; +using System.Collections.Generic; namespace MediaBrowser.Controller.LiveTv { @@ -23,6 +23,12 @@ namespace MediaBrowser.Controller.LiveTv /// The identifier. public string Id { get; set; } + /// + /// Gets or sets the URL. + /// + /// The URL. + public string Url { get; set; } + /// /// Gets or sets the status. /// -- cgit v1.2.3 From 37f22e67f97e5fdfcaf55fa0ee3d7e5bdab08e77 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 19 Apr 2015 11:54:20 -0400 Subject: added a photo view --- MediaBrowser.Api/UserLibrary/UserViewsService.cs | 6 +-- .../Entities/UserViewBuilder.cs | 33 +++++++++++---- .../EntryPoints/ExternalPortForwarding.cs | 48 ++++------------------ .../Localization/Server/server.json | 4 +- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 1 + .../MediaBrowser.WebDashboard.csproj | 6 +++ 6 files changed, 45 insertions(+), 53 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 9b00b42f76..43d8dbc169 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -88,7 +88,7 @@ namespace MediaBrowser.Api.UserLibrary var views = user.RootFolder .GetChildren(user, true) - .OfType() + .OfType() .Where(i => IsEligibleForSpecialView(i)) .ToList(); @@ -105,9 +105,9 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(list); } - private bool IsEligibleForSpecialView(CollectionFolder view) + private bool IsEligibleForSpecialView(ICollectionFolder view) { - var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music }; + var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos }; return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index a6d123fe86..1672bda926 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -121,7 +121,6 @@ namespace MediaBrowser.Controller.Entities } case CollectionType.Books: - case CollectionType.Photos: case CollectionType.HomeVideos: case CollectionType.MusicVideos: return GetResult(queryParent.GetChildren(user, true), queryParent, query); @@ -138,6 +137,9 @@ namespace MediaBrowser.Controller.Entities case CollectionType.BoxSets: return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false); + case CollectionType.Photos: + return await GetPhotosView(queryParent, user, query).ConfigureAwait(false); + case CollectionType.TvShows: return await GetTvView(queryParent, user, query).ConfigureAwait(false); @@ -247,16 +249,16 @@ namespace MediaBrowser.Controller.Entities return GetFavoriteSongs(queryParent, user, query); default: - { - if (queryParent is UserView) - { - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query); - } - else { - return GetResult(queryParent.GetChildren(user, true), queryParent, query); + if (queryParent is UserView) + { + return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query); + } + else + { + return GetResult(queryParent.GetChildren(user, true), queryParent, query); + } } - } } } @@ -645,6 +647,19 @@ namespace MediaBrowser.Controller.Entities }), parent, query); } + private async Task> GetPhotosView(Folder queryParent, User user, InternalItemsQuery query) + { + if (query.Recursive) + { + var mediaTypes = new[] { MediaType.Video, MediaType.Photo }; + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Photos, string.Empty }, i => (i is PhotoAlbum || mediaTypes.Contains(i.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) && FilterItem(i, query)); + + return PostFilterAndSort(items, queryParent, null, query); + } + + return GetResult(queryParent.GetChildren(user, true), queryParent, query); + } + private async Task> GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 966e0a3e48..3fa0df7608 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -1,5 +1,4 @@ -using System.Linq; -using MediaBrowser.Controller; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; @@ -139,55 +138,24 @@ namespace MediaBrowser.Server.Implementations.EntryPoints // On some systems the device discovered event seems to fire repeatedly // This check will help ensure we're not trying to port map the same device over and over - List currentMappings = null; - - try - { - currentMappings = device.GetAllMappings().ToList(); - } - catch (NotSupportedException) - { - } - var address = device.LocalAddress.ToString(); if (!_createdRules.Contains(address)) { _createdRules.Add(address); - CreatePortMap(device, currentMappings, _appHost.HttpPort, _config.Configuration.PublicPort); - CreatePortMap(device, currentMappings, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort); + CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort); + CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort); } } - private void CreatePortMap(INatDevice device, List currentMappings, int privatePort, int publicPort) + private void CreatePortMap(INatDevice device, int privatePort, int publicPort) { - var hasMapping = false; - - if (currentMappings != null) - { - hasMapping = currentMappings.Any(i => i.PublicPort == publicPort && i.PrivatePort == privatePort); - } - else + _logger.Debug("Creating port map on port {0}", privatePort); + device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort) { - try - { - var mapping = device.GetSpecificMapping(Protocol.Tcp, publicPort); - hasMapping = mapping != null; - } - catch (NotSupportedException) - { - } - } - - if (!hasMapping) - { - _logger.Debug("Creating port map on port {0}", privatePort); - device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort) - { - Description = _appHost.Name - }); - } + Description = _appHost.Name + }); } // As I said before, this method will be never invoked. You can remove it. diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 1affc43bf8..f464dad4ba 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1433,5 +1433,7 @@ "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.", "HeaderViewStyles": "View Styles", "LabelSelectViewStyles": "Enable rich presentations for:", - "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders." + "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.", + "TabPhotos": "Photos", + "TabVideos": "Videos" } diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 90af13b579..030d687918 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -470,6 +470,7 @@ namespace MediaBrowser.WebDashboard.Api "notificationlist.js", "notificationsetting.js", "notificationsettings.js", + "photos.js", "playlists.js", "playlistedit.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 7abe2ded98..5c4aab1e4f 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -132,6 +132,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -147,6 +150,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest -- cgit v1.2.3 From 9e0c73ef1946cd49de43f972839af90c465dcfb1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 19 Apr 2015 15:17:17 -0400 Subject: live tv fixes --- Emby.Drawing/ImageProcessor.cs | 32 ++++++++-------------- MediaBrowser.Api/ApiEntryPoint.cs | 27 +++++++++++++++--- MediaBrowser.Controller/Entities/BaseItem.cs | 22 ++++----------- MediaBrowser.Controller/Entities/ItemImageInfo.cs | 6 ---- .../Manager/ItemImageProvider.cs | 1 - .../Dto/DtoService.cs | 5 +--- .../Library/UserViewManager.cs | 10 +++++-- .../LiveTv/LiveTvMediaSourceProvider.cs | 11 ++++++-- 8 files changed, 55 insertions(+), 59 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 6d600c646b..55c6f6455e 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -158,22 +158,19 @@ namespace Emby.Drawing } var dateModified = options.Image.DateModified; - var length = options.Image.Length; if (options.CropWhiteSpace) { - var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified, length).ConfigureAwait(false); + var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; - length = tuple.Item3; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(new ItemImageInfo { - Length = length, DateModified = dateModified, Type = options.Image.Type, Path = originalImagePath @@ -182,7 +179,6 @@ namespace Emby.Drawing originalImagePath = tuple.Item1; dateModified = tuple.Item2; - length = tuple.Item3; } var originalImageSize = GetImageSize(originalImagePath, dateModified); @@ -199,7 +195,7 @@ namespace Emby.Drawing var quality = options.Quality ?? 90; var outputFormat = GetOutputFormat(options.OutputFormat); - var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, length, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); + var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); @@ -240,11 +236,10 @@ namespace Emby.Drawing /// /// Crops whitespace from an image, caches the result, and returns the cached path /// - private async Task> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified, long length) + private async Task> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified) { var name = originalImagePath; name += "datemodified=" + dateModified.Ticks; - name += "length=" + length; var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath)); @@ -270,7 +265,7 @@ namespace Emby.Drawing // We have to have a catch-all here because some of the .net image methods throw a plain old Exception _logger.ErrorException("Error cropping image {0}", ex, originalImagePath); - return new Tuple(originalImagePath, dateModified, length); + return new Tuple(originalImagePath, dateModified); } finally { @@ -280,11 +275,9 @@ namespace Emby.Drawing return GetResult(croppedImagePath); } - private Tuple GetResult(string path) + private Tuple GetResult(string path) { - var file = new FileInfo(path); - - return new Tuple(path, _fileSystem.GetLastWriteTimeUtc(file), file.Length); + return new Tuple(path, _fileSystem.GetLastWriteTimeUtc(path)); } /// @@ -295,7 +288,7 @@ namespace Emby.Drawing /// /// Gets the cache file path based on a set of parameters /// - private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, long length, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor) + private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor) { var filename = originalPath; @@ -306,7 +299,6 @@ namespace Emby.Drawing filename += "quality=" + quality; filename += "datemodified=" + dateModified.Ticks; - filename += "length=" + length; filename += "f=" + format; @@ -492,17 +484,16 @@ namespace Emby.Drawing var originalImagePath = image.Path; var dateModified = image.DateModified; var imageType = image.Type; - var length = image.Length; // Optimization if (imageEnhancers.Count == 0) { - return (originalImagePath + dateModified.Ticks + string.Empty + length).GetMD5().ToString("N"); + return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N"); } // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList(); - cacheKeys.Add(originalImagePath + dateModified.Ticks + string.Empty + length); + cacheKeys.Add(originalImagePath + dateModified.Ticks); return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N"); } @@ -525,7 +516,7 @@ namespace Emby.Drawing return result.Item1; } - private async Task> GetEnhancedImage(ItemImageInfo image, + private async Task> GetEnhancedImage(ItemImageInfo image, IHasImages item, int imageIndex, List enhancers) @@ -533,7 +524,6 @@ namespace Emby.Drawing var originalImagePath = image.Path; var dateModified = image.DateModified; var imageType = image.Type; - var length = image.Length; try { @@ -553,7 +543,7 @@ namespace Emby.Drawing _logger.Error("Error enhancing image", ex); } - return new Tuple(originalImagePath, dateModified, length); + return new Tuple(originalImagePath, dateModified); } /// diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 26d3c6200f..f59b1b7df2 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -341,14 +341,17 @@ namespace MediaBrowser.Api timerDuration = 60000; } + job.PingTimeout = timerDuration; + job.LastPingDate = DateTime.UtcNow; + // Don't start the timer for playback checkins with progressive streaming if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn) { - job.StartKillTimer(timerDuration, OnTranscodeKillTimerStopped); + job.StartKillTimer(OnTranscodeKillTimerStopped); } else { - job.ChangeKillTimerIfStarted(timerDuration); + job.ChangeKillTimerIfStarted(); } } @@ -360,6 +363,15 @@ namespace MediaBrowser.Api { var job = (TranscodingJob)state; + if (!job.HasExited && job.Type != TranscodingJobType.Progressive) + { + if ((DateTime.UtcNow - job.LastPingDate).TotalMilliseconds < job.PingTimeout) + { + job.StartKillTimer(OnTranscodeKillTimerStopped); + return; + } + } + Logger.Debug("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId); KillTranscodingJob(job, path => true); @@ -626,6 +638,9 @@ namespace MediaBrowser.Api private readonly object _timerLock = new object(); + public DateTime LastPingDate { get; set; } + public int PingTimeout { get; set; } + public TranscodingJob(ILogger logger) { Logger = logger; @@ -654,12 +669,14 @@ namespace MediaBrowser.Api } } - public void StartKillTimer(int intervalMs, TimerCallback callback) + public void StartKillTimer(TimerCallback callback) { CheckHasExited(); lock (_timerLock) { + var intervalMs = PingTimeout; + if (KillTimer == null) { Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); @@ -673,7 +690,7 @@ namespace MediaBrowser.Api } } - public void ChangeKillTimerIfStarted(int intervalMs) + public void ChangeKillTimerIfStarted() { CheckHasExited(); @@ -681,6 +698,8 @@ namespace MediaBrowser.Api { if (KillTimer != null) { + var intervalMs = PingTimeout; + Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); KillTimer.Change(intervalMs, Timeout.Infinite); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 73ede8179b..22efd3fba7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1512,7 +1512,6 @@ namespace MediaBrowser.Controller.Entities image.Path = file.FullName; image.DateModified = imageInfo.DateModified; - image.Length = imageInfo.Length; } } @@ -1622,14 +1621,11 @@ namespace MediaBrowser.Controller.Entities return null; } - var fileInfo = new FileInfo(path); - return new ItemImageInfo { Path = path, - DateModified = FileSystem.GetLastWriteTimeUtc(fileInfo), - Type = imageType, - Length = fileInfo.Length + DateModified = FileSystem.GetLastWriteTimeUtc(path), + Type = imageType }; } @@ -1690,7 +1686,6 @@ namespace MediaBrowser.Controller.Entities else { existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage); - existing.Length = ((FileInfo)newImage).Length; } } @@ -1716,8 +1711,7 @@ namespace MediaBrowser.Controller.Entities { Path = file.FullName, Type = type, - DateModified = FileSystem.GetLastWriteTimeUtc(file), - Length = ((FileInfo)file).Length + DateModified = FileSystem.GetLastWriteTimeUtc(file) }; } @@ -1756,15 +1750,9 @@ namespace MediaBrowser.Controller.Entities FileSystem.SwapFiles(path1, path2); - var file1 = new FileInfo(info1.Path); - var file2 = new FileInfo(info2.Path); - // Refresh these values - info1.DateModified = FileSystem.GetLastWriteTimeUtc(file1); - info2.DateModified = FileSystem.GetLastWriteTimeUtc(file2); - - info1.Length = file1.Length; - info2.Length = file2.Length; + info1.DateModified = FileSystem.GetLastWriteTimeUtc(info1.Path); + info2.DateModified = FileSystem.GetLastWriteTimeUtc(info2.Path); return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); } diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs index 1122de4032..b36b818ffe 100644 --- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs +++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs @@ -11,12 +11,6 @@ namespace MediaBrowser.Controller.Entities /// The path. public string Path { get; set; } - /// - /// Gets or sets the length. - /// - /// The length. - public long Length { get; set; } - /// /// Gets or sets the type. /// diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index a3b5691500..fc47b0259a 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -384,7 +384,6 @@ namespace MediaBrowser.Providers.Manager else { currentImage.DateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo); - currentImage.Length = ((FileInfo) image.FileInfo).Length; } } else diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 190b8fcf4c..f44b7b5a84 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -828,14 +828,11 @@ namespace MediaBrowser.Server.Implementations.Dto if (!string.IsNullOrEmpty(chapterInfo.ImagePath)) { - var file = new FileInfo(chapterInfo.ImagePath); - dto.ImageTag = GetImageCacheTag(item, new ItemImageInfo { Path = chapterInfo.ImagePath, Type = ImageType.Chapter, - DateModified = _fileSystem.GetLastWriteTimeUtc(file), - Length = file.Length + DateModified = _fileSystem.GetLastWriteTimeUtc(chapterInfo.ImagePath) }); } diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index a21b19e04c..823599fe51 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -202,9 +202,15 @@ namespace MediaBrowser.Server.Implementations.Library public async Task GetUserView(List parents, string viewType, string sortName, User user, CancellationToken cancellationToken) { + var name = _localizationManager.GetLocalizedString("ViewType" + viewType); + if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase))) { - var name = parents[0].Name; + if (!string.IsNullOrWhiteSpace(parents[0].Name)) + { + name = parents[0].Name; + } + var parentId = parents[0].Id; var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase); @@ -226,8 +232,6 @@ namespace MediaBrowser.Server.Implementations.Library } else { - var name = _localizationManager.GetLocalizedString("ViewType" + viewType); - return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 84b4053a19..38c93a6964 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) { - var inputPaths = new[] { mediaSource.Path }; + var originalRuntime = mediaSource.RunTimeTicks; var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest { @@ -131,8 +131,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video, ExtractChapters = false - }, cancellationToken) - .ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); mediaSource.Bitrate = info.Bitrate; mediaSource.Container = info.Container; @@ -146,6 +145,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv mediaSource.DefaultSubtitleStreamIndex = null; + // Null this out so that it will be treated like a live stream + if (!originalRuntime.HasValue) + { + mediaSource.RunTimeTicks = null; + } + var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio); if (audioStream == null || audioStream.Index == -1) -- cgit v1.2.3 From 623874ec8b6ea3c0fb2c9b0643298af1b94a4e6d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Apr 2015 14:04:02 -0400 Subject: improve live stream pinging --- MediaBrowser.Api/ApiEntryPoint.cs | 44 +++++++++++--- MediaBrowser.Api/Playback/BaseStreamingService.cs | 1 + MediaBrowser.Controller/Library/ILibraryManager.cs | 2 + .../Configuration/ServerConfiguration.cs | 2 +- MediaBrowser.Model/Dlna/StreamBuilder.cs | 10 ++- .../MediaInfo/FFProbeVideoInfo.cs | 71 ++++++++++++++-------- .../Library/LibraryManager.cs | 14 ++++- .../Library/UserViewManager.cs | 37 ++++++----- 8 files changed, 124 insertions(+), 57 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index f59b1b7df2..e76dcb4a48 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Configuration; @@ -40,6 +41,7 @@ namespace MediaBrowser.Api private readonly ISessionManager _sessionManager; private readonly IFileSystem _fileSystem; + private readonly IMediaSourceManager _mediaSourceManager; public readonly SemaphoreSlim TranscodingStartLock = new SemaphoreSlim(1, 1); @@ -49,12 +51,15 @@ namespace MediaBrowser.Api /// The logger. /// The session manager. /// The configuration. - public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem) + /// The file system. + /// The media source manager. + public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager) { Logger = logger; _sessionManager = sessionManager; _config = config; _fileSystem = fileSystem; + _mediaSourceManager = mediaSourceManager; Instance = this; } @@ -133,6 +138,7 @@ namespace MediaBrowser.Api /// /// The path. /// The play session identifier. + /// The live stream identifier. /// The transcoding job identifier. /// The type. /// The process. @@ -142,6 +148,7 @@ namespace MediaBrowser.Api /// TranscodingJob. public TranscodingJob OnTranscodeBeginning(string path, string playSessionId, + string liveStreamId, string transcodingJobId, TranscodingJobType type, Process process, @@ -160,7 +167,8 @@ namespace MediaBrowser.Api DeviceId = deviceId, CancellationTokenSource = cancellationTokenSource, Id = transcodingJobId, - PlaySessionId = playSessionId + PlaySessionId = playSessionId, + LiveStreamId = liveStreamId }; _activeTranscodingJobs.Add(job); @@ -323,7 +331,7 @@ namespace MediaBrowser.Api } } - private void PingTimer(TranscodingJob job, bool isProgressCheckIn) + private async void PingTimer(TranscodingJob job, bool isProgressCheckIn) { if (job.HasExited) { @@ -353,6 +361,18 @@ namespace MediaBrowser.Api { job.ChangeKillTimerIfStarted(); } + + if (!string.IsNullOrWhiteSpace(job.LiveStreamId)) + { + try + { + await _mediaSourceManager.PingLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.ErrorException("Error closing live stream", ex); + } + } } /// @@ -365,9 +385,11 @@ namespace MediaBrowser.Api if (!job.HasExited && job.Type != TranscodingJobType.Progressive) { - if ((DateTime.UtcNow - job.LastPingDate).TotalMilliseconds < job.PingTimeout) + var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds; + + if (timeSinceLastPing < job.PingTimeout) { - job.StartKillTimer(OnTranscodeKillTimerStopped); + job.StartKillTimer(OnTranscodeKillTimerStopped, job.PingTimeout); return; } } @@ -589,6 +611,11 @@ namespace MediaBrowser.Api /// The play session identifier. public string PlaySessionId { get; set; } /// + /// Gets or sets the live stream identifier. + /// + /// The live stream identifier. + public string LiveStreamId { get; set; } + /// /// Gets or sets the path. /// /// The path. @@ -670,13 +697,16 @@ namespace MediaBrowser.Api } public void StartKillTimer(TimerCallback callback) + { + StartKillTimer(callback, PingTimeout); + } + + public void StartKillTimer(TimerCallback callback, int intervalMs) { CheckHasExited(); lock (_timerLock) { - var intervalMs = PingTimeout; - if (KillTimer == null) { Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 520c3b9dc7..923af3816a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1010,6 +1010,7 @@ namespace MediaBrowser.Api.Playback var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, state.Request.PlaySessionId, + state.MediaSource.LiveStreamId, transcodingId, TranscodingJobType, process, diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index d16589f07f..c009121154 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -309,6 +309,7 @@ namespace MediaBrowser.Controller.Library /// The parent identifier. /// Type of the view. /// Name of the sort. + /// The unique identifier. /// The cancellation token. /// Task<UserView>. Task GetNamedView(User user, @@ -316,6 +317,7 @@ namespace MediaBrowser.Controller.Library string parentId, string viewType, string sortName, + string uniqueId, CancellationToken cancellationToken); /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 72f9174388..ac9bd6b08f 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Configuration /// /// true if [enable user specific user views]; otherwise, false. public bool EnableUserSpecificUserViews { get; set; } - + /// /// Gets or sets the value pointing to the file system where the ssl certiifcate is located.. /// diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index e8ef171aa7..30da8bb4c9 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -456,10 +456,8 @@ namespace MediaBrowser.Model.Dlna playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } - if (!playlistItem.AudioBitrate.HasValue) - { - playlistItem.AudioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec); - } + int audioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec); + playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate); int? maxBitrateSetting = options.GetMaxBitrate(); // Honor max rate @@ -472,9 +470,9 @@ namespace MediaBrowser.Model.Dlna videoBitrate -= playlistItem.AudioBitrate.Value; } + // Make sure the video bitrate is lower than bitrate settings but at least 64k int currentValue = playlistItem.VideoBitrate ?? videoBitrate; - - playlistItem.VideoBitrate = Math.Min(videoBitrate, currentValue); + playlistItem.VideoBitrate = Math.Max(Math.Min(videoBitrate, currentValue), 64000); } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index f4d8ddb1a8..b53e313168 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -218,7 +218,7 @@ namespace MediaBrowser.Providers.MediaInfo await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false); - FetchEmbeddedInfo(video, mediaInfo); + FetchEmbeddedInfo(video, mediaInfo, options); video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1270); @@ -358,11 +358,13 @@ namespace MediaBrowser.Providers.MediaInfo return _blurayExaminer.GetDiscInfo(path); } - private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data) + private void FetchEmbeddedInfo(Video video, Model.MediaInfo.MediaInfo data, MetadataRefreshOptions options) { + var isFullRefresh = options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; + if (!video.LockedFields.Contains(MetadataFields.OfficialRating)) { - if (!string.IsNullOrWhiteSpace(data.OfficialRating)) + if (!string.IsNullOrWhiteSpace(data.OfficialRating) || isFullRefresh) { video.OfficialRating = data.OfficialRating; } @@ -370,54 +372,75 @@ namespace MediaBrowser.Providers.MediaInfo if (!video.LockedFields.Contains(MetadataFields.Cast)) { - video.People.Clear(); - - foreach (var person in data.People) + if (video.People.Count == 0 || isFullRefresh) { - video.AddPerson(new PersonInfo + video.People.Clear(); + + foreach (var person in data.People) { - Name = person.Name, - Type = person.Type, - Role = person.Role - }); + video.AddPerson(new PersonInfo + { + Name = person.Name, + Type = person.Type, + Role = person.Role + }); + } } } if (!video.LockedFields.Contains(MetadataFields.Genres)) { - video.Genres.Clear(); - - foreach (var genre in data.Genres) + if (video.Genres.Count == 0 || isFullRefresh) { - video.AddGenre(genre); + video.Genres.Clear(); + + foreach (var genre in data.Genres) + { + video.AddGenre(genre); + } } } if (!video.LockedFields.Contains(MetadataFields.Studios)) { - video.Studios.Clear(); - - foreach (var studio in data.Studios) + if (video.Studios.Count == 0 || isFullRefresh) { - video.AddStudio(studio); + video.Studios.Clear(); + + foreach (var studio in data.Studios) + { + video.AddStudio(studio); + } } } if (data.ProductionYear.HasValue) { - video.ProductionYear = data.ProductionYear; + if (!video.ProductionYear.HasValue || isFullRefresh) + { + video.ProductionYear = data.ProductionYear; + } } if (data.PremiereDate.HasValue) { - video.PremiereDate = data.PremiereDate; + if (!video.PremiereDate.HasValue || isFullRefresh) + { + video.PremiereDate = data.PremiereDate; + } } if (data.IndexNumber.HasValue) { - video.IndexNumber = data.IndexNumber; + if (!video.IndexNumber.HasValue || isFullRefresh) + { + video.IndexNumber = data.IndexNumber; + } } if (data.ParentIndexNumber.HasValue) { - video.ParentIndexNumber = data.ParentIndexNumber; + if (!video.ParentIndexNumber.HasValue || isFullRefresh) + { + video.ParentIndexNumber = data.ParentIndexNumber; + } } // If we don't have a ProductionYear try and get it from PremiereDate @@ -428,7 +451,7 @@ namespace MediaBrowser.Providers.MediaInfo if (!video.LockedFields.Contains(MetadataFields.Overview)) { - if (!string.IsNullOrWhiteSpace(data.Overview)) + if (string.IsNullOrWhiteSpace(video.Overview) || isFullRefresh) { video.Overview = data.Overview; } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index e99d01d54f..dcdf2aa7dc 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1602,7 +1602,7 @@ namespace MediaBrowser.Server.Implementations.Library { if (ConfigurationManager.Configuration.EnableUserSpecificUserViews) { - return await GetNamedViewInternal(user, name, null, viewType, sortName, cancellationToken) + return await GetNamedViewInternal(user, name, null, viewType, sortName, null, cancellationToken) .ConfigureAwait(false); } @@ -1662,6 +1662,7 @@ namespace MediaBrowser.Server.Implementations.Library string parentId, string viewType, string sortName, + string uniqueId, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(parentId)) @@ -1669,7 +1670,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("parentId"); } - return GetNamedViewInternal(user, name, parentId, viewType, sortName, cancellationToken); + return GetNamedViewInternal(user, name, parentId, viewType, sortName, uniqueId, cancellationToken); } private async Task GetNamedViewInternal(User user, @@ -1677,6 +1678,7 @@ namespace MediaBrowser.Server.Implementations.Library string parentId, string viewType, string sortName, + string uniqueId, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(name)) @@ -1684,7 +1686,13 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } - var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); + var idValues = "37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty); + if (!string.IsNullOrWhiteSpace(uniqueId)) + { + idValues += uniqueId; + } + + var id = GetNewItemId(idValues, typeof(UserView)); var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N")); diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 823599fe51..5cff9046a3 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); } parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) @@ -105,7 +105,7 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false)); } parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType)) @@ -113,7 +113,7 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); } parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)) @@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); } parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) @@ -129,7 +129,7 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false)); } parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) @@ -137,12 +137,12 @@ namespace MediaBrowser.Server.Implementations.Library if (parents.Count > 0) { - list.Add(await GetUserView(parents, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(parents, list, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false)); } if (user.Configuration.DisplayFoldersView) { - list.Add(await GetUserView(new List(), CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(new List(), list, CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); } if (query.IncludeExternalContent) @@ -169,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Library if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) { //list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false)); - list.Add(await GetUserView(new List(), CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); + list.Add(await GetUserView(new List(), list, CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); } } @@ -190,7 +190,9 @@ namespace MediaBrowser.Server.Implementations.Library public Task GetUserSubView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken) { - return _libraryManager.GetNamedView(user, name, parentId, type, sortName, cancellationToken); + var uniqueId = parentId + "subview" + type; + + return _libraryManager.GetNamedView(user, name, parentId, type, sortName, uniqueId, cancellationToken); } public Task GetUserSubView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken) @@ -200,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.Library return GetUserSubView(name, parentId, type, user, sortName, cancellationToken); } - public async Task GetUserView(List parents, string viewType, string sortName, User user, CancellationToken cancellationToken) + public async Task GetUserView(List parents, List currentViews, string viewType, string sortName, User user, CancellationToken cancellationToken) { var name = _localizationManager.GetLocalizedString("ViewType" + viewType); @@ -215,7 +217,12 @@ namespace MediaBrowser.Server.Implementations.Library var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase); - if (_config.Configuration.EnableUserSpecificUserViews || !enableRichView) + if (!enableRichView || currentViews.OfType().Any(i => string.Equals(i.ViewType, viewType, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase))) + { + return await GetUserView(parentId, name, viewType, enableRichView, sortName, user, cancellationToken).ConfigureAwait(false); + } + + if (_config.Configuration.EnableUserSpecificUserViews) { viewType = enableRichView ? viewType : null; var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); @@ -230,16 +237,14 @@ namespace MediaBrowser.Server.Implementations.Library return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); } - else - { - return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); - } + + return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); } public Task GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, User user, CancellationToken cancellationToken) { viewType = enableRichView ? viewType : null; - return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, cancellationToken); + return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, null, cancellationToken); } public List>> GetLatestItems(LatestItemsQuery request) -- cgit v1.2.3