Kaynağa Gözat

Merge pull request #1830 from MediaBrowser/dev

Dev
Luke 9 yıl önce
ebeveyn
işleme
b6b5a0e6dc

+ 19 - 35
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -402,47 +402,31 @@ namespace MediaBrowser.Controller.Entities.TV
         public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
         public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, Season parentSeason, bool includeSpecials)
         {
         {
             var seasonNumber = parentSeason.IndexNumber;
             var seasonNumber = parentSeason.IndexNumber;
-            if (!includeSpecials || (seasonNumber.HasValue && seasonNumber.Value == 0))
-            {
-                var seasonPresentationKey = parentSeason.PresentationUniqueKey;
+            var seasonPresentationKey = parentSeason.PresentationUniqueKey;
 
 
-                return episodes.Where(i =>
-                {
-                    if ((i.ParentIndexNumber ?? -1) == seasonNumber)
-                    {
-                        return true;
-                    }
-                    if (!i.ParentIndexNumber.HasValue)
-                    {
-                        var season = i.Season;
-                        return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
-                    }
-
-                    return false;
-                });
-            }
-            else
-            {
-                var seasonPresentationKey = parentSeason.PresentationUniqueKey;
+            var supportSpecialsInSeason = includeSpecials && seasonNumber.HasValue && seasonNumber.Value != 0;
 
 
-                return episodes.Where(episode =>
+            return episodes.Where(episode =>
+            {
+                var currentSeasonNumber = supportSpecialsInSeason ? episode.AiredSeasonNumber : episode.ParentIndexNumber;
+                if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
                 {
                 {
-                    var currentSeasonNumber = episode.AiredSeasonNumber;
+                    return true;
+                }
 
 
-                    if (currentSeasonNumber.HasValue && seasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber.Value)
-                    {
-                        return true;
-                    }
+                if (!currentSeasonNumber.HasValue && !seasonNumber.HasValue && parentSeason.LocationType == LocationType.Virtual)
+                {
+                    return true;
+                }
 
 
-                    if (!episode.ParentIndexNumber.HasValue)
-                    {
-                        var season = episode.Season;
-                        return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
-                    }
+                if (!episode.ParentIndexNumber.HasValue)
+                {
+                    var season = episode.Season;
+                    return season != null && string.Equals(season.PresentationUniqueKey, seasonPresentationKey, StringComparison.OrdinalIgnoreCase);
+                }
 
 
-                    return false;
-                });
-            }
+                return false;
+            });
         }
         }
 
 
         protected override bool GetBlockUnratedValue(UserPolicy config)
         protected override bool GetBlockUnratedValue(UserPolicy config)

+ 1 - 0
MediaBrowser.Controller/LiveTv/IListingsProvider.cs

@@ -15,5 +15,6 @@ namespace MediaBrowser.Controller.LiveTv
         Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
         Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
         Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
         Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
         Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
         Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
+        Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 8 - 0
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
 
 
 namespace MediaBrowser.Controller.LiveTv
 namespace MediaBrowser.Controller.LiveTv
 {
 {
@@ -385,5 +386,12 @@ namespace MediaBrowser.Controller.LiveTv
         List<NameValuePair> GetSatIniMappings();
         List<NameValuePair> GetSatIniMappings();
 
 
         Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
         Task<List<ChannelInfo>> GetSatChannelScanResult(TunerHostInfo info, CancellationToken cancellationToken);
+
+        Task<List<ChannelInfo>> GetChannelsFromListingsProvider(string id, CancellationToken cancellationToken);
+
+        event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+        event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+        event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+        event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
     }
     }
 }
 }

+ 14 - 0
MediaBrowser.Controller/LiveTv/TimerEventInfo.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+    public class TimerEventInfo
+    {
+        public string Id { get; set; }
+        public string ProgramId { get; set; }
+    }
+}

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -218,6 +218,7 @@
     <Compile Include="LiveTv\ProgramInfo.cs" />
     <Compile Include="LiveTv\ProgramInfo.cs" />
     <Compile Include="LiveTv\RecordingInfo.cs" />
     <Compile Include="LiveTv\RecordingInfo.cs" />
     <Compile Include="LiveTv\SeriesTimerInfo.cs" />
     <Compile Include="LiveTv\SeriesTimerInfo.cs" />
+    <Compile Include="LiveTv\TimerEventInfo.cs" />
     <Compile Include="LiveTv\TimerInfo.cs" />
     <Compile Include="LiveTv\TimerInfo.cs" />
     <Compile Include="Localization\ILocalizationManager.cs" />
     <Compile Include="Localization\ILocalizationManager.cs" />
     <Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />
     <Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" />

+ 13 - 0
MediaBrowser.Model/LiveTv/LiveTvOptions.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Model.LiveTv
 namespace MediaBrowser.Model.LiveTv
 {
 {
@@ -90,5 +91,17 @@ namespace MediaBrowser.Model.LiveTv
             EnableAllTuners = true;
             EnableAllTuners = true;
             ChannelMappings = new NameValuePair[] {};
             ChannelMappings = new NameValuePair[] {};
         }
         }
+
+        public string GetMappedChannel(string channelNumber)
+        {
+            foreach (NameValuePair mapping in ChannelMappings)
+            {
+                if (StringHelper.EqualsIgnoreCase(mapping.Name, channelNumber))
+                {
+                    return mapping.Value;
+                }
+            }
+            return channelNumber;
+        }
     }
     }
 }
 }

+ 83 - 0
MediaBrowser.Server.Implementations/EntryPoints/RecordingNotifier.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Server.Implementations.EntryPoints
+{
+    public class RecordingNotifier : IServerEntryPoint
+    {
+        private readonly ILiveTvManager _liveTvManager;
+        private readonly ISessionManager _sessionManager;
+        private readonly IUserManager _userManager;
+        private readonly ILogger _logger;
+
+        public RecordingNotifier(ISessionManager sessionManager, IUserManager userManager, ILogger logger, ILiveTvManager liveTvManager)
+        {
+            _sessionManager = sessionManager;
+            _userManager = userManager;
+            _logger = logger;
+            _liveTvManager = liveTvManager;
+        }
+
+        public void Run()
+        {
+            _liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
+            _liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
+            _liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
+            _liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
+        }
+
+        private void _liveTvManager_SeriesTimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+        {
+            SendMessage("SeriesTimerCreated", e.Argument);
+        }
+
+        private void _liveTvManager_TimerCreated(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+        {
+            SendMessage("TimerCreated", e.Argument);
+        }
+
+        private void _liveTvManager_SeriesTimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+        {
+            SendMessage("SeriesTimerCancelled", e.Argument);
+        }
+
+        private void _liveTvManager_TimerCancelled(object sender, Model.Events.GenericEventArgs<TimerEventInfo> e)
+        {
+            SendMessage("TimerCancelled", e.Argument);
+        }
+
+        private async void SendMessage(string name, TimerEventInfo info)
+        {
+            var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).ToList();
+
+            foreach (var user in users)
+            {
+                try
+                {
+                    await _sessionManager.SendMessageToUserSessions<TimerEventInfo>(user.Id.ToString("N"), name, info, CancellationToken.None);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error sending message", ex);
+                }
+            }
+        }
+
+        public void Dispose()
+        {
+            _liveTvManager.TimerCancelled -= _liveTvManager_TimerCancelled;
+            _liveTvManager.SeriesTimerCancelled -= _liveTvManager_SeriesTimerCancelled;
+            _liveTvManager.TimerCreated -= _liveTvManager_TimerCreated;
+            _liveTvManager.SeriesTimerCreated -= _liveTvManager_SeriesTimerCreated;
+        }
+    }
+}

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -1000,7 +1000,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                         result.Item3.Release();
                         result.Item3.Release();
                     }
                     }
 
 
-                    _libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
+                    _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
                 }
                 }
             }
             }
             catch (OperationCanceledException)
             catch (OperationCanceledException)

+ 5 - 0
MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -869,6 +869,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             return GetHeadends(info, country, location, CancellationToken.None);
             return GetHeadends(info, country, location, CancellationToken.None);
         }
         }
 
 
+        public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+        {
+            return new List<ChannelInfo>();
+        }
+
         public class ScheduleDirect
         public class ScheduleDirect
         {
         {
             public class Token
             public class Token

+ 9 - 2
MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

@@ -107,11 +107,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             var reader = new XmlTvReader(info.Path, GetLanguage(), null);
             var reader = new XmlTvReader(info.Path, GetLanguage(), null);
             var results = reader.GetChannels().ToList();
             var results = reader.GetChannels().ToList();
 
 
-            if (channels != null && channels.Count > 0)
+            if (channels != null)
             {
             {
                 channels.ForEach(c =>
                 channels.ForEach(c =>
                 {
                 {
-                    var match = results.FirstOrDefault(r => r.Id == c.Id);
+                    var channelNumber = info.GetMappedChannel(c.Number);
+                    var match = results.FirstOrDefault(r => string.Equals(r.Id, channelNumber, StringComparison.OrdinalIgnoreCase));
+
                     if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
                     if (match != null && match.Icon != null && !String.IsNullOrEmpty(match.Icon.Source))
                     {
                     {
                         c.ImageUrl = match.Icon.Source;
                         c.ImageUrl = match.Icon.Source;
@@ -142,5 +144,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
             // Should this method be async?
             // Should this method be async?
             return Task.FromResult(results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList());
             return Task.FromResult(results.Select(c => new NameIdPair() { Id = c.Id, Name = c.DisplayName }).ToList());
         }
         }
+
+        public async Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken)
+        {
+            return new List<ChannelInfo>();
+        }
     }
     }
 }
 }

+ 46 - 0
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -30,6 +30,8 @@ using System.Threading.Tasks;
 using CommonIO;
 using CommonIO;
 using IniParser;
 using IniParser;
 using IniParser.Model;
 using IniParser.Model;
+using MediaBrowser.Common.Events;
+using MediaBrowser.Model.Events;
 
 
 namespace MediaBrowser.Server.Implementations.LiveTv
 namespace MediaBrowser.Server.Implementations.LiveTv
 {
 {
@@ -64,6 +66,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
         private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
 
 
+        public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+        public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+        public event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+        public event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
+
         public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
         public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager, IFileSystem fileSystem)
         {
         {
             _config = config;
             _config = config;
@@ -1759,6 +1766,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
+
+            EventHelper.QueueEventIfNotNull(TimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+            {
+                Argument = new TimerEventInfo
+                {
+                    Id = id
+                }
+            }, _logger);
         }
         }
 
 
         public async Task CancelSeriesTimer(string id)
         public async Task CancelSeriesTimer(string id)
@@ -1774,6 +1789,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
+
+            EventHelper.QueueEventIfNotNull(SeriesTimerCancelled, this, new GenericEventArgs<TimerEventInfo>
+            {
+                Argument = new TimerEventInfo
+                {
+                    Id = id
+                }
+            }, _logger);
         }
         }
 
 
         public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
         public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
@@ -1993,6 +2016,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
             await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
             _logger.Info("New recording scheduled");
             _logger.Info("New recording scheduled");
+
+            EventHelper.QueueEventIfNotNull(TimerCreated, this, new GenericEventArgs<TimerEventInfo>
+            {
+                Argument = new TimerEventInfo
+                {
+                    ProgramId = info.ProgramId
+                }
+            }, _logger);
         }
         }
 
 
         public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
         public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
@@ -2007,6 +2038,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
             await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
             _lastRecordingRefreshTime = DateTime.MinValue;
             _lastRecordingRefreshTime = DateTime.MinValue;
+
+            EventHelper.QueueEventIfNotNull(SeriesTimerCreated, this, new GenericEventArgs<TimerEventInfo>
+            {
+                Argument = new TimerEventInfo
+                {
+                    ProgramId = info.ProgramId
+                }
+            }, _logger);
         }
         }
 
 
         public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
         public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
@@ -2521,5 +2560,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
         {
             return new TunerHosts.SatIp.ChannelScan(_logger).Scan(info, cancellationToken);
             return new TunerHosts.SatIp.ChannelScan(_logger).Scan(info, cancellationToken);
         }
         }
+
+        public Task<List<ChannelInfo>> GetChannelsFromListingsProvider(string id, CancellationToken cancellationToken)
+        {
+            var info = GetConfiguration().ListingProviders.First(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
+            var provider = _listingProviders.First(i => string.Equals(i.Type, info.Type, StringComparison.OrdinalIgnoreCase));
+            return provider.GetChannels(info, cancellationToken);
+        }
     }
     }
 }
 }

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -142,6 +142,7 @@
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
     <Compile Include="EntryPoints\Notifications\Notifications.cs" />
     <Compile Include="EntryPoints\Notifications\Notifications.cs" />
     <Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" />
     <Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" />
+    <Compile Include="EntryPoints\RecordingNotifier.cs" />
     <Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
     <Compile Include="EntryPoints\RefreshUsersMetadata.cs" />
     <Compile Include="EntryPoints\UsageEntryPoint.cs" />
     <Compile Include="EntryPoints\UsageEntryPoint.cs" />
     <Compile Include="Connect\ConnectEntryPoint.cs" />
     <Compile Include="Connect\ConnectEntryPoint.cs" />

+ 2 - 1
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -381,7 +381,8 @@ namespace MediaBrowser.Server.Startup.Common
                 new OmdbEpisodeProviderMigration(ServerConfigurationManager),
                 new OmdbEpisodeProviderMigration(ServerConfigurationManager),
                 new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
                 new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
                 new DbMigration(ServerConfigurationManager, TaskManager),
                 new DbMigration(ServerConfigurationManager, TaskManager),
-                new FolderViewSettingMigration(ServerConfigurationManager, UserManager)
+                new FolderViewSettingMigration(ServerConfigurationManager, UserManager),
+                new CollectionGroupingMigration(ServerConfigurationManager, UserManager)
             };
             };
 
 
             foreach (var task in migrations)
             foreach (var task in migrations)