diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 147abd171a..d477008a5a 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -491,7 +491,7 @@ namespace Emby.Server.Implementations.Dto } } - //if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess)) + if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess)) { dto.PlayAccess = item.GetPlayAccess(user); } @@ -1639,7 +1639,7 @@ namespace Emby.Server.Implementations.Dto var width = size.Width; var height = size.Height; - if (width == 0 || height == 0) + if (width.Equals(0) || height.Equals(0)) { return null; } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index a7ccafd693..d18004f963 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -2543,6 +2543,22 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public CancellationTokenSource CancellationTokenSource { get; set; } } + private const int TunerDiscoveryDurationMs = 3000; + + public async Task> DiscoverTuners(CancellationToken cancellationToken) + { + var list = new List(); + + foreach (var host in _liveTvManager.TunerHosts) + { + var discoveredDevices = await DiscoverDevices(host, TunerDiscoveryDurationMs, cancellationToken).ConfigureAwait(false); + + list.AddRange(discoveredDevices); + } + + return list; + } + public async Task ScanForTunerDeviceChanges(CancellationToken cancellationToken) { foreach (var host in _liveTvManager.TunerHosts) @@ -2553,7 +2569,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private async Task ScanForTunerDeviceChanges(ITunerHost host, CancellationToken cancellationToken) { - var discoveredDevices = await DiscoverDevices(host, 3000, cancellationToken).ConfigureAwait(false); + var discoveredDevices = await DiscoverDevices(host, TunerDiscoveryDurationMs, cancellationToken).ConfigureAwait(false); var configuredDevices = GetConfiguration().TunerHosts .Where(i => string.Equals(i.Type, host.Type, StringComparison.OrdinalIgnoreCase)) diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index c22bb11710..21c4006a6e 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -205,6 +205,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings } programInfo.ShowId = uniqueString.GetMD5().ToString("N"); + + // If we don't have valid episode info, assume it's a unique program, otherwise recordings might be skipped + if (programInfo.IsSeries && !programInfo.IsRepeat) + { + if ((programInfo.EpisodeNumber ?? 0) == 0) + { + programInfo.ShowId = programInfo.ShowId + programInfo.StartDate.Ticks.ToString(CultureInfo.InvariantCulture); + } + } } // Construct an id from the channel and start date diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index de39d3838e..92ef24deab 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -160,6 +160,11 @@ namespace Emby.Server.Implementations.LiveTv }).ToList(); } + public Task> DiscoverTuners(CancellationToken cancellationToken) + { + return EmbyTV.EmbyTV.Current.DiscoverTuners(cancellationToken); + } + void service_DataSourceChanged(object sender, EventArgs e) { if (!_isDisposed) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 79fa9bb61f..c9cd289e7e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -135,8 +135,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { // Check to make sure the tuner is available // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error - if (hostsWithChannel.Count > 1 && - !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false)) + if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false)) { Logger.Error("Tuner is not currently available"); continue; @@ -208,6 +207,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts foreach (var host in hostsWithChannel) { + if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + try { var liveStream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); @@ -243,7 +247,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts protected abstract Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken); - protected abstract bool IsValidChannelId(string channelId); + protected virtual string ChannelIdPrefix + { + get + { + return Type + "_"; + } + } + protected virtual bool IsValidChannelId(string channelId) + { + if (string.IsNullOrWhiteSpace(channelId)) + { + throw new ArgumentNullException("channelId"); + } + + return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); + } protected LiveTvOptions GetConfiguration() { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index dbcabd1742..d9c0807ded 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -56,7 +56,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun get { return "hdhomerun"; } } - private const string ChannelIdPrefix = "hdhr_"; + protected override string ChannelIdPrefix + { + get + { + return "hdhr_"; + } + } private string GetChannelId(TunerHostInfo info, Channels i) { @@ -559,26 +565,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return list; } - protected override bool IsValidChannelId(string channelId) - { - if (string.IsNullOrWhiteSpace(channelId)) - { - throw new ArgumentNullException("channelId"); - } - - return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); - } - protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var profile = streamId.Split('_')[0]; Logger.Info("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelId, streamId, profile); - if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase)) - { - throw new ArgumentException("Channel not found"); - } var hdhrId = GetHdHrIdFromChannelId(channelId); var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false); @@ -706,6 +698,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var modelInfo = await GetModelInfo(hostInfo, false, cancellationToken).ConfigureAwait(false); hostInfo.DeviceId = modelInfo.DeviceID; + hostInfo.FriendlyName = modelInfo.FriendlyName; return hostInfo; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index cc0ae0983b..4ec70f8026 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -46,8 +46,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts get { return "M3U Tuner"; } } - private const string ChannelIdPrefix = "m3u_"; - protected override async Task> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken) { var result = await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, !info.EnableTvgId, cancellationToken).ConfigureAwait(false); @@ -87,16 +85,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts } } - protected override bool IsValidChannelId(string channelId) - { - if (string.IsNullOrWhiteSpace(channelId)) - { - throw new ArgumentNullException("channelId"); - } - - return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); - } - protected override async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { var urlHash = info.Url.GetMD5().ToString("N"); diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 120f445c22..64a41acef7 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -408,6 +408,7 @@ namespace Emby.Server.Implementations.Localization new LocalizatonOption{ Name="Italian", Value="it"}, new LocalizatonOption{ Name="Kazakh", Value="kk"}, new LocalizatonOption{ Name="Norwegian Bokmål", Value="nb"}, + new LocalizatonOption{ Name="Persian", Value="fa"}, new LocalizatonOption{ Name="Polish", Value="pl"}, new LocalizatonOption{ Name="Portuguese (Brazil)", Value="pt-BR"}, new LocalizatonOption{ Name="Portuguese (Portugal)", Value="pt-PT"}, diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 639021762a..2f7d049361 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -677,7 +677,14 @@ namespace MediaBrowser.Api.LiveTv [Authenticated] public class GetTunerHostTypes : IReturn> { - + + } + + [Route("/LiveTv/Tuners/Discvover", "GET")] + [Authenticated] + public class DiscoverTuners : IReturn> + { + } public class LiveTvService : BaseApiService @@ -730,6 +737,12 @@ namespace MediaBrowser.Api.LiveTv }; } + public async Task Get(DiscoverTuners request) + { + var result = await _liveTvManager.DiscoverTuners(CancellationToken.None).ConfigureAwait(false); + return ToOptimizedResult(result); + } + public async Task Get(GetLiveStreamFile request) { var directStreamProvider = (await _liveTvManager.GetEmbyTvLiveStream(request.Id).ConfigureAwait(false)) as IDirectStreamProvider; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 78f907d61a..8906264191 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -614,7 +614,8 @@ namespace MediaBrowser.Controller.Entities Timestamp = i.Timestamp, Type = type, PlayableStreamFileNames = i.PlayableStreamFileNames.ToList(), - SupportsDirectStream = i.VideoType == VideoType.VideoFile + SupportsDirectStream = i.VideoType == VideoType.VideoFile, + IsRemote = i.IsShortcut }; if (info.Protocol == MediaProtocol.File) diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index b3467fbbce..0dda303a3e 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -382,6 +382,7 @@ namespace MediaBrowser.Controller.LiveTv List ListingProviders { get; } List GetTunerHostTypes(); + Task> DiscoverTuners(CancellationToken cancellationToken); event EventHandler> SeriesTimerCancelled; event EventHandler> TimerCancelled; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ebcc9853ae..6482b68290 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -185,6 +185,12 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } + // obviously don't do this for strm files + if (string.Equals(container, "strm", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + return container; } diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 7af0acc593..9cd656fa7e 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -16,6 +16,8 @@ public bool EnableAutomaticSeriesGrouping { get; set; } public bool EnableEmbeddedTitles { get; set; } + public int AutomaticRefreshIntervalDays { get; set; } + /// /// Gets or sets the preferred metadata language. /// diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index bdfe13c1d2..59a2278a1f 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -45,12 +45,21 @@ namespace MediaBrowser.Providers.Manager var updateType = ItemUpdateType.None; var requiresRefresh = false; + var libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item); + if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) { // TODO: If this returns true, should we instead just change metadata refresh mode to Full? requiresRefresh = item.RequiresRefresh(); } + if (!requiresRefresh && + libraryOptions.AutomaticRefreshIntervalDays > 0 && + (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays) + { + requiresRefresh = true; + } + var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem); var localImagesFailed = false; @@ -116,8 +125,6 @@ namespace MediaBrowser.Providers.Manager } } - LibraryOptions libraryOptions = null; - // Next run remote image providers, but only if local image providers didn't throw an exception if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly) { @@ -125,11 +132,6 @@ namespace MediaBrowser.Providers.Manager if (providers.Count > 0) { - if (libraryOptions == null) - { - libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item); - } - var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false); updateType = updateType | result.UpdateType; @@ -177,11 +179,6 @@ namespace MediaBrowser.Providers.Manager item.DateLastRefreshed = default(DateTime); } - if (libraryOptions == null) - { - libraryOptions = LibraryManager.GetLibraryOptions((BaseItem)item); - } - // Save to database await SaveItem(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false); } diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 1e03f1169b..54133b718a 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.696 + 3.0.697 Emby.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index d6777dad1a..e59460c94d 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.696 + 3.0.697 Emby.Server.Core Emby Team ebr,Luke,scottisafool diff --git a/SharedVersion.cs b/SharedVersion.cs index 825a8b919e..b001cfb52b 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.7.4")] +[assembly: AssemblyVersion("3.2.7.5")]