You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	Added TimerProvider
This commit is contained in:
		| @@ -93,6 +93,7 @@ | ||||
|     <Compile Include="AutoMoq\Unity\AutoMockingContainerExtension.cs"> | ||||
|       <SubType>Code</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="TimerProviderTest.cs" /> | ||||
|     <Compile Include="SyncProviderTest.cs" /> | ||||
|     <Compile Include="RootDirProviderTest.cs" /> | ||||
|     <Compile Include="IndexerProviderTest.cs" /> | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| using MbUnit.Framework; | ||||
| using System.Threading; | ||||
| using MbUnit.Framework; | ||||
| using NzbDrone.Core.Repository.Quality; | ||||
|  | ||||
| namespace NzbDrone.Core.Test | ||||
| @@ -13,8 +14,8 @@ namespace NzbDrone.Core.Test | ||||
|          *  | ||||
|          */ | ||||
|  | ||||
|  | ||||
|         [Test] | ||||
|         [Timeout(1)] | ||||
|         [Row("Sonny.With.a.Chance.S02E15", 2, 15)] | ||||
|         [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", 3, 1)] | ||||
|         [Row("Two.and.a.Half.Me.103.720p.HDTV.X264-DIMENSION", 1, 3)] | ||||
| @@ -40,6 +41,7 @@ namespace NzbDrone.Core.Test | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         [Timeout(1)] | ||||
|         [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", QualityTypes.BDRip)] | ||||
|         [Row("WEEDS.S03E01-06.DUAL.BDRip.AC3.-HELLYWOOD", QualityTypes.BDRip)] | ||||
|         [Row("Two.and.a.Half.Men.S08E05.720p.HDTV.X264-DIMENSION", QualityTypes.HDTV)] | ||||
| @@ -66,9 +68,10 @@ namespace NzbDrone.Core.Test | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         [Timeout(1)] | ||||
|         [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", 3, new[] { 1, 2, 3, 4, 5, 6 })] | ||||
|         [Row("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", 1, new[] {3, 4})] | ||||
|         [Row("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", 3, new[] {1, 2})] | ||||
|         [Row("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", 1, new[] { 3, 4 })] | ||||
|         [Row("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", 3, new[] { 1, 2 })] | ||||
|         [Row("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", 1, new[] { 1, 2 })] | ||||
|         [Row("Big Time Rush 1x01 to 10 480i DD2 0 Sianto", 1, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })] | ||||
|         [Row("White.Collar.2x04.2x05.720p.BluRay-FUTV", 2, new[] { 4, 5 })] | ||||
|   | ||||
							
								
								
									
										110
									
								
								NzbDrone.Core.Test/TimerProviderTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								NzbDrone.Core.Test/TimerProviderTest.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| using System; | ||||
| using System.Linq; | ||||
| using System.Collections.Generic; | ||||
| using AutoMoq; | ||||
| using MbUnit.Framework; | ||||
| using Moq; | ||||
| using NzbDrone.Core.Providers; | ||||
| using NzbDrone.Core.Providers.Core; | ||||
| using NzbDrone.Core.Providers.Timers; | ||||
|  | ||||
| namespace NzbDrone.Core.Test | ||||
| { | ||||
|     [TestFixture] | ||||
|     // ReSharper disable InconsistentNaming | ||||
|     public class TimerProviderTest | ||||
|     { | ||||
|         [Test] | ||||
|         public void Run_Timers() | ||||
|         { | ||||
|  | ||||
|             IEnumerable<ITimer> fakeTimers = new List<ITimer> { new FakeTimer() }; | ||||
|             var mocker = new AutoMoqer(); | ||||
|  | ||||
|             mocker.SetConstant(MockLib.GetEmptyRepository()); | ||||
|             mocker.SetConstant(fakeTimers); | ||||
|  | ||||
|             var timerProvider = mocker.Resolve<TimerProvider>(); | ||||
|             timerProvider.Initialize(); | ||||
|             timerProvider.Run(); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void Init_Timers() | ||||
|         { | ||||
|             var fakeTimer = new FakeTimer(); | ||||
|             IEnumerable<ITimer> fakeTimers = new List<ITimer> { fakeTimer }; | ||||
|             var mocker = new AutoMoqer(); | ||||
|  | ||||
|             mocker.SetConstant(MockLib.GetEmptyRepository()); | ||||
|             mocker.SetConstant(fakeTimers); | ||||
|  | ||||
|             var timerProvider = mocker.Resolve<TimerProvider>(); | ||||
|             timerProvider.Initialize(); | ||||
|  | ||||
|             var timers = timerProvider.All(); | ||||
|  | ||||
|  | ||||
|             //Assert | ||||
|             Assert.Count(1, timers); | ||||
|             Assert.AreEqual(fakeTimer.DefaultInterval, timers[0].Interval); | ||||
|             Assert.AreEqual(fakeTimer.Name, timers[0].Name); | ||||
|             Assert.AreEqual(fakeTimer.GetType().ToString(), timers[0].TypeName); | ||||
|             Assert.AreEqual(DateTime.MinValue, timers[0].LastExecution); | ||||
|             Assert.IsTrue(timers[0].Enable); | ||||
|  | ||||
|  | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void Init_Timers_only_registers_once() | ||||
|         { | ||||
|             var repo = MockLib.GetEmptyRepository(); | ||||
|  | ||||
|             for (int i = 0; i < 2; i++) | ||||
|             { | ||||
|                 var fakeTimer = new FakeTimer(); | ||||
|                 IEnumerable<ITimer> fakeTimers = new List<ITimer> { fakeTimer }; | ||||
|                 var mocker = new AutoMoqer(); | ||||
|  | ||||
|                 mocker.SetConstant(repo); | ||||
|                 mocker.SetConstant(fakeTimers); | ||||
|  | ||||
|                 var timerProvider = mocker.Resolve<TimerProvider>(); | ||||
|                 timerProvider.Initialize(); | ||||
|             } | ||||
|  | ||||
|             var mocker2 = new AutoMoqer(); | ||||
|  | ||||
|             mocker2.SetConstant(repo); | ||||
|             var assertTimerProvider = mocker2.Resolve<TimerProvider>(); | ||||
|  | ||||
|             var timers = assertTimerProvider.All(); | ||||
|  | ||||
|  | ||||
|             //Assert | ||||
|             Assert.Count(1, timers); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public class FakeTimer : ITimer | ||||
|     { | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "FakeTimer"; } | ||||
|         } | ||||
|  | ||||
|         public int DefaultInterval | ||||
|         { | ||||
|             get { return 15; } | ||||
|         } | ||||
|  | ||||
|         public void Start() | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -10,6 +10,7 @@ using NzbDrone.Core.Instrumentation; | ||||
| using NzbDrone.Core.Providers; | ||||
| using NzbDrone.Core.Providers.Core; | ||||
| using NzbDrone.Core.Providers.Indexer; | ||||
| using NzbDrone.Core.Providers.Timers; | ||||
| using NzbDrone.Core.Repository; | ||||
| using NzbDrone.Core.Repository.Quality; | ||||
| using SubSonic.DataProviders; | ||||
| @@ -22,7 +23,6 @@ namespace NzbDrone.Core | ||||
|         private static StandardKernel _kernel; | ||||
|         private static readonly Object KernelLock = new object(); | ||||
|         private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | ||||
|         private static string _startupPath; | ||||
|  | ||||
|         public static String AppPath | ||||
|         { | ||||
| @@ -36,21 +36,6 @@ namespace NzbDrone.Core | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static string ExecutablePath | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 //var uri = new Uri(Assembly.EscapedCodeBase); | ||||
|                 //return Path.GetDirectoryName(uri.LocalPath); | ||||
|                 return Directory.GetCurrentDirectory(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static string StartupPath | ||||
|         { | ||||
|             get { return _startupPath; } | ||||
|         } | ||||
|  | ||||
|         public static StandardKernel NinjectKernel | ||||
|         { | ||||
|             get | ||||
| @@ -70,19 +55,16 @@ namespace NzbDrone.Core | ||||
|                 Logger.Debug("Binding Ninject's Kernel"); | ||||
|                 _kernel = new StandardKernel(); | ||||
|  | ||||
|                 //Store the startup path  | ||||
|                 _startupPath = AppPath; | ||||
|  | ||||
|                 //Sqlite | ||||
|                 var AppDataPath = new DirectoryInfo(Path.Combine(AppPath, "App_Data")); | ||||
|                 if (!AppDataPath.Exists) AppDataPath.Create(); | ||||
|                 var appDataPath = new DirectoryInfo(Path.Combine(AppPath, "App_Data")); | ||||
|                 if (!appDataPath.Exists) appDataPath.Create(); | ||||
|  | ||||
|                 string connectionString = String.Format("Data Source={0};Version=3;", | ||||
|                                                         Path.Combine(AppDataPath.FullName, "nzbdrone.db")); | ||||
|                                                         Path.Combine(appDataPath.FullName, "nzbdrone.db")); | ||||
|                 var dbProvider = ProviderFactory.GetProvider(connectionString, "System.Data.SQLite"); | ||||
|  | ||||
|                 string logConnectionString = String.Format("Data Source={0};Version=3;", | ||||
|                                                            Path.Combine(AppDataPath.FullName, "log.db")); | ||||
|                                                            Path.Combine(appDataPath.FullName, "log.db")); | ||||
|                 var logDbProvider = ProviderFactory.GetProvider(logConnectionString, "System.Data.SQLite"); | ||||
|  | ||||
|  | ||||
| @@ -99,7 +81,6 @@ namespace NzbDrone.Core | ||||
|                 _kernel.Bind<HttpProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<SeriesProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<SeasonProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<RssSyncProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<EpisodeProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<UpcomingEpisodesProvider>().ToSelf().InSingletonScope(); | ||||
|                 _kernel.Bind<DiskProvider>().ToSelf().InSingletonScope(); | ||||
| @@ -127,12 +108,6 @@ namespace NzbDrone.Core | ||||
|                 ForceMigration(_kernel.Get<IRepository>()); | ||||
|                 SetupDefaultQualityProfiles(_kernel.Get<IRepository>()); //Setup the default QualityProfiles on start-up | ||||
|  | ||||
|                 //Get the Timers going | ||||
|                 var config = _kernel.Get<ConfigProvider>(); | ||||
|                 var timer = _kernel.Get<TimerProvider>(); | ||||
|                 timer.SetRssSyncTimer(Convert.ToInt32(config.GetValue("SyncFrequency", "15", true))); | ||||
|                 timer.StartRssSyncTimer(); | ||||
|  | ||||
|                 BindIndexers(); | ||||
|             } | ||||
|         } | ||||
| @@ -140,6 +115,7 @@ namespace NzbDrone.Core | ||||
|         private static void BindIndexers() | ||||
|         { | ||||
|             _kernel.Bind<IndexerProviderBase>().To<NzbsOrgProvider>().InSingletonScope(); | ||||
|  | ||||
|             var indexers = _kernel.GetAll<IndexerProviderBase>(); | ||||
|             _kernel.Get<IndexerProvider>().InitializeIndexers(indexers.ToList()); | ||||
|         } | ||||
| @@ -154,7 +130,7 @@ namespace NzbDrone.Core | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         ///   This method forces IISExpress process to exit with the host application | ||||
|         ///   Forces IISExpress process to exit with the host application | ||||
|         /// </summary> | ||||
|         public static void DedicateToHost() | ||||
|         { | ||||
| @@ -187,7 +163,6 @@ namespace NzbDrone.Core | ||||
|             Process.GetCurrentProcess().Kill(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         private static void SetupDefaultQualityProfiles(IRepository repository) | ||||
|         { | ||||
|             var sd = new QualityProfile | ||||
|   | ||||
| @@ -1,14 +0,0 @@ | ||||
| using System; | ||||
|  | ||||
| namespace NzbDrone.Core.Helpers | ||||
| { | ||||
|     public static class ServerHelper | ||||
|     { | ||||
|         public static string GetServerHostname() | ||||
|         { | ||||
|             //Both these seem to return the same result... Is on better than the other? | ||||
|             return Environment.MachineName; | ||||
|             //return Dns.GetHostName(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -163,14 +163,17 @@ | ||||
|     <Compile Include="Helpers\EpisodeRenameHelper.cs" /> | ||||
|     <Compile Include="Helpers\EpisodeSortingHelper.cs" /> | ||||
|     <Compile Include="Helpers\SceneNameHelper.cs" /> | ||||
|     <Compile Include="Helpers\ServerHelper.cs" /> | ||||
|     <Compile Include="Instrumentation\LogLevel.cs" /> | ||||
|     <Compile Include="Instrumentation\LogProvider.cs" /> | ||||
|     <Compile Include="Instrumentation\SubsonicTarget.cs" /> | ||||
|     <Compile Include="Instrumentation\ExceptioneerTarget.cs" /> | ||||
|     <Compile Include="Instrumentation\NlogWriter.cs" /> | ||||
|     <Compile Include="Providers\Timers\TimerProvider.cs" /> | ||||
|     <Compile Include="Providers\Indexer\NzbMatrixFeedProvider.cs" /> | ||||
|     <Compile Include="Providers\Indexer\NzbsRUsFeedProvider.cs" /> | ||||
|     <Compile Include="Providers\Timers\ITimer.cs" /> | ||||
|     <Compile Include="Providers\Timers\RssSyncTimer.cs" /> | ||||
|     <Compile Include="Repository\TimerSetting.cs" /> | ||||
|     <Compile Include="Repository\IndexerSetting.cs" /> | ||||
|     <Compile Include="Model\EpisodeParseResult.cs" /> | ||||
|     <Compile Include="Model\EpisodeRenameModel.cs" /> | ||||
| @@ -187,12 +190,10 @@ | ||||
|     <Compile Include="Providers\HistoryProvider.cs" /> | ||||
|     <Compile Include="Providers\BacklogProvider.cs" /> | ||||
|     <Compile Include="Providers\IndexerProvider.cs" /> | ||||
|     <Compile Include="Providers\RssSyncProvider.cs" /> | ||||
|     <Compile Include="Providers\PostProcessingProvider.cs" /> | ||||
|     <Compile Include="Providers\QualityProvider.cs" /> | ||||
|     <Compile Include="Providers\RenameProvider.cs" /> | ||||
|     <Compile Include="Providers\RootDirProvider.cs" /> | ||||
|     <Compile Include="Providers\TimerProvider.cs" /> | ||||
|     <Compile Include="Providers\UpcomingEpisodesProvider.cs" /> | ||||
|     <Compile Include="Providers\XbmcProvider.cs" /> | ||||
|     <Compile Include="Repository\EpisodeFile.cs" /> | ||||
|   | ||||
| @@ -116,7 +116,7 @@ namespace NzbDrone.Core | ||||
|                 if (match.Count != 0) | ||||
|                 { | ||||
|                     var seriesName = NormalizeTitle(match[0].Groups["title"].Value); | ||||
|                     var year = 0; | ||||
|                     int year; | ||||
|                     Int32.TryParse(match[0].Groups["year"].Value, out year); | ||||
|  | ||||
|                     if (year < 1900 || year > DateTime.Now.Year + 1) | ||||
| @@ -130,12 +130,11 @@ namespace NzbDrone.Core | ||||
|                                      { | ||||
|                                          SeriesTitle = seriesName, | ||||
|                                          SeasonNumber = seasonNumber, | ||||
|                                          Year = year | ||||
|                                          Year = year, | ||||
|                                          Quality = ParseQuality(title) | ||||
|                                      }; | ||||
|  | ||||
|  | ||||
|                     result.Quality = ParseQuality(title); | ||||
|  | ||||
|                     Logger.Trace("Season Parsed. {0}", result); | ||||
|                     return result; | ||||
|                 } | ||||
| @@ -160,14 +159,7 @@ namespace NzbDrone.Core | ||||
|                 if (match.Count != 0) | ||||
|                 { | ||||
|                     var seriesName = NormalizeTitle(match[0].Groups["title"].Value); | ||||
|                     var year = 0; | ||||
|                     Int32.TryParse(match[0].Groups["year"].Value, out year); | ||||
|  | ||||
|                     if (year < 1900 || year > DateTime.Now.Year + 1) | ||||
|                     { | ||||
|                         year = 0; | ||||
|                     } | ||||
|  | ||||
|             | ||||
|                     Logger.Trace("Series Parsed. {0}", seriesName); | ||||
|                     return seriesName; | ||||
|                 } | ||||
|   | ||||
| @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Providers | ||||
|             return _repository.Single<IndexerSetting>(s => s.IndexProviderType == type.ToString()); | ||||
|         } | ||||
|  | ||||
|         public IndexerSetting GetSettings(int id) | ||||
|         public virtual IndexerSetting GetSettings(int id) | ||||
|         { | ||||
|             return _repository.Single<IndexerSetting>(s => s.Id == id); | ||||
|         } | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| namespace NzbDrone.Core.Providers | ||||
| { | ||||
|     public class RssSyncProvider | ||||
|     { | ||||
|         public virtual void Begin() | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -51,7 +51,7 @@ namespace NzbDrone.Core.Providers | ||||
|  | ||||
|             XDocument xDoc = XDocument.Parse(response); | ||||
|  | ||||
|             //If an Error Occurred, retuyrn) | ||||
|             //If an Error Occurred, return) | ||||
|             if (xDoc.Descendants("error").Count() != 0) | ||||
|                 return false; | ||||
|  | ||||
|   | ||||
| @@ -1,130 +0,0 @@ | ||||
| using System; | ||||
| using System.Timers; | ||||
| using NLog; | ||||
|  | ||||
| namespace NzbDrone.Core.Providers | ||||
| { | ||||
|     public class TimerProvider | ||||
|     { | ||||
|         private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | ||||
|         private readonly EpisodeProvider _episodeProvider; | ||||
|         private readonly MediaFileProvider _mediaFileProvider; | ||||
|  | ||||
|         private readonly Timer _minuteTimer; | ||||
|         private readonly RssSyncProvider _rssSyncProvider; | ||||
|         private readonly Timer _rssSyncTimer; | ||||
|         private readonly SeasonProvider _seasonProvider; | ||||
|         private readonly SeriesProvider _seriesProvider; | ||||
|         private DateTime _rssSyncNextInterval; | ||||
|  | ||||
|         public TimerProvider(RssSyncProvider rssSyncProvider, SeriesProvider seriesProvider, | ||||
|                              SeasonProvider seasonProvider, EpisodeProvider episodeProvider, | ||||
|                              MediaFileProvider mediaFileProvider) | ||||
|         { | ||||
|             _rssSyncProvider = rssSyncProvider; | ||||
|             _seriesProvider = seriesProvider; | ||||
|             _seasonProvider = seasonProvider; | ||||
|             _episodeProvider = episodeProvider; | ||||
|             _mediaFileProvider = mediaFileProvider; | ||||
|  | ||||
|             _rssSyncTimer = new Timer(); | ||||
|             _minuteTimer = new Timer(60000); | ||||
|         } | ||||
|  | ||||
|         public virtual void ResetRssSyncTimer() | ||||
|         { | ||||
|             double interval = _rssSyncTimer.Interval; | ||||
|             _rssSyncTimer.Interval = interval; | ||||
|         } | ||||
|  | ||||
|         public virtual void StartRssSyncTimer() | ||||
|         { | ||||
|             if (_rssSyncTimer.Interval < 900000) | ||||
|                 //If Timer is less than 15 minutes, throw an error! This should also be handled when saving the config, though a user could by-pass it by editing the DB directly... TNO (Trust No One) | ||||
|             { | ||||
|                 Logger.Error("RSS Sync Frequency is invalid, please set the interval first"); | ||||
|                 throw new InvalidOperationException("RSS Sync Frequency Invalid"); | ||||
|             } | ||||
|  | ||||
|             _rssSyncTimer.Elapsed += RunRssSync; | ||||
|             _rssSyncTimer.Start(); | ||||
|             _rssSyncNextInterval = DateTime.Now.AddMilliseconds(_rssSyncTimer.Interval); | ||||
|         } | ||||
|  | ||||
|         public virtual void StopRssSyncTimer() | ||||
|         { | ||||
|             _rssSyncTimer.Stop(); | ||||
|         } | ||||
|  | ||||
|         public virtual void SetRssSyncTimer(int minutes) | ||||
|         { | ||||
|             long ms = minutes*60*1000; | ||||
|             _rssSyncTimer.Interval = ms; | ||||
|         } | ||||
|  | ||||
|         public virtual TimeSpan RssSyncTimeLeft() | ||||
|         { | ||||
|             return _rssSyncNextInterval.Subtract(DateTime.Now); | ||||
|         } | ||||
|  | ||||
|         public virtual DateTime NextRssSyncTime() | ||||
|         { | ||||
|             return _rssSyncNextInterval; | ||||
|         } | ||||
|  | ||||
|         public virtual void StartMinuteTimer() | ||||
|         { | ||||
|             _minuteTimer.Elapsed += MinuteTimer_Elapsed; | ||||
|             _minuteTimer.Start(); | ||||
|         } | ||||
|  | ||||
|         public virtual void StopMinuteTimer() | ||||
|         { | ||||
|             _minuteTimer.Stop(); | ||||
|         } | ||||
|  | ||||
|         private void RunRssSync(object obj, ElapsedEventArgs args) | ||||
|         { | ||||
|             _rssSyncNextInterval = DateTime.Now.AddMilliseconds(_rssSyncTimer.Interval); | ||||
|             _rssSyncProvider.Begin(); | ||||
|         } | ||||
|  | ||||
|         private void MinuteTimer_Elapsed(object obj, ElapsedEventArgs args) | ||||
|         { | ||||
|             //Check to see if anything should be run at this time, if so run it | ||||
|  | ||||
|             var now = DateTime.Now; | ||||
|  | ||||
|             //Daily (Except Sunday) 03:00 - Update the lastest season for all TV Shows | ||||
|             if (now.Hour == 3 && now.Minute == 0 && now.DayOfWeek != DayOfWeek.Sunday) | ||||
|             { | ||||
|                 foreach (var series in _seriesProvider.GetAllSeries()) | ||||
|                 { | ||||
|                     var season = _seasonProvider.GetLatestSeason(series.SeriesId); | ||||
|                     _episodeProvider.RefreshEpisodeInfo(season); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             //Sunday 03:00 - Update all TV Shows | ||||
|             if (now.Hour == 3 && now.Minute == 0 && now.DayOfWeek == DayOfWeek.Sunday) | ||||
|             { | ||||
|                 foreach (var series in _seriesProvider.GetAllSeries()) | ||||
|                 { | ||||
|                     _episodeProvider.RefreshEpisodeInfo(series.SeriesId); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             //Daily 00:00 (Midnight) - Cleanup (removed) EpisodeFiles + Scan for New EpisodeFiles | ||||
|             if (now.Hour == 0 && now.Minute == 0) | ||||
|             { | ||||
|                 foreach (var series in _seriesProvider.GetAllSeries()) | ||||
|                 { | ||||
|                     _mediaFileProvider.CleanUp(series.EpisodeFiles); | ||||
|                     _mediaFileProvider.Scan(series); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             throw new NotImplementedException(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								NzbDrone.Core/Providers/Timers/ITimer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								NzbDrone.Core/Providers/Timers/ITimer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| namespace NzbDrone.Core.Providers.Timers | ||||
| { | ||||
|     public interface ITimer | ||||
|     { | ||||
|         string Name { get; } | ||||
|  | ||||
|         int DefaultInterval { get; } | ||||
|  | ||||
|         void Start(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										39
									
								
								NzbDrone.Core/Providers/Timers/RssSyncTimer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								NzbDrone.Core/Providers/Timers/RssSyncTimer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| using System.Linq; | ||||
| using NLog; | ||||
|  | ||||
| namespace NzbDrone.Core.Providers.Timers | ||||
| { | ||||
|     public class RssSyncTimer : ITimer | ||||
|     { | ||||
|         private readonly IndexerProvider _indexerProvider; | ||||
|  | ||||
|         private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|         public RssSyncTimer(IndexerProvider indexerProvider) | ||||
|         { | ||||
|             _indexerProvider = indexerProvider; | ||||
|         } | ||||
|  | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "RSS Sync"; } | ||||
|         } | ||||
|  | ||||
|         public int DefaultInterval | ||||
|         { | ||||
|             get { return 15; } | ||||
|         } | ||||
|  | ||||
|         public void Start() | ||||
|         { | ||||
|             Logger.Info("Doing Things!!!!"); | ||||
|  | ||||
|             var indexers = _indexerProvider.AllIndexers().Where(c => c.Enable); | ||||
|  | ||||
|             foreach (var indexerSetting in indexers) | ||||
|             { | ||||
|                  | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										123
									
								
								NzbDrone.Core/Providers/Timers/TimerProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								NzbDrone.Core/Providers/Timers/TimerProvider.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Linq; | ||||
| using NLog; | ||||
| using NzbDrone.Core.Repository; | ||||
| using SubSonic.Repository; | ||||
|  | ||||
| namespace NzbDrone.Core.Providers.Timers | ||||
| { | ||||
|     public class TimerProvider | ||||
|     { | ||||
|         private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | ||||
|         private readonly IRepository _repository; | ||||
|         private readonly IEnumerable<ITimer> _timerJobs; | ||||
|  | ||||
|         private static readonly object ExecutionLock = new object(); | ||||
|         private static bool _isRunning; | ||||
|  | ||||
|         public TimerProvider(IRepository repository, IEnumerable<ITimer> timerJobs) | ||||
|         { | ||||
|             _repository = repository; | ||||
|             _timerJobs = timerJobs; | ||||
|         } | ||||
|  | ||||
|         public TimerProvider() { } | ||||
|  | ||||
|         public virtual List<TimerSetting> All() | ||||
|         { | ||||
|             return _repository.All<TimerSetting>().ToList(); | ||||
|         } | ||||
|  | ||||
|         public virtual void SaveSettings(TimerSetting settings) | ||||
|         { | ||||
|             if (settings.Id == 0) | ||||
|             { | ||||
|                 Logger.Debug("Adding timer settings for {0}", settings.Name); | ||||
|                 _repository.Add(settings); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Logger.Debug("Updating timer settings for {0}", settings.Name); | ||||
|                 _repository.Update(settings); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public virtual void Run() | ||||
|         { | ||||
|             lock (ExecutionLock) | ||||
|             { | ||||
|                 if (_isRunning) | ||||
|                 { | ||||
|                     Logger.Info("Another instance of timer is already running. Ignoring request."); | ||||
|                     return; | ||||
|                 } | ||||
|                 _isRunning = true; | ||||
|             } | ||||
|  | ||||
|             Logger.Trace("Getting list of timers needing to be executed"); | ||||
|  | ||||
|             var pendingTimers = All().Where( | ||||
|                                                      t => t.Enable && | ||||
|                                                      (DateTime.Now - t.LastExecution) > TimeSpan.FromMinutes(t.Interval) | ||||
|                 ); | ||||
|  | ||||
|             foreach (var pendingTimer in pendingTimers) | ||||
|             { | ||||
|                 Logger.Info("Attempting to start timer [{0}]. Last executing {1}", pendingTimer.Name, pendingTimer.LastExecution); | ||||
|                 var timerClass = _timerJobs.Where(t => t.GetType().ToString() == pendingTimer.TypeName).FirstOrDefault(); | ||||
|                 ForceExecute(timerClass.GetType()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void ForceExecute(Type timerType) | ||||
|         { | ||||
|             var timerClass = _timerJobs.Where(t => t.GetType() == timerType).FirstOrDefault(); | ||||
|             if (timerClass == null) | ||||
|             { | ||||
|                 Logger.Error("Unable to locate implantation for [{0}]. Make sure its properly registered.", timerType.ToString()); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 var sw = Stopwatch.StartNew(); | ||||
|                 timerClass.Start(); | ||||
|                 sw.Stop(); | ||||
|                 Logger.Info("timer [{0}] finished executing successfully. Duration {1}", timerClass.Name, sw.Elapsed.ToString()); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 Logger.Error("An error has occurred while executing timer job " + timerClass.Name, e); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public virtual void Initialize() | ||||
|         { | ||||
|             Logger.Info("Initializing timer jobs. Count {0}", _timerJobs.Count()); | ||||
|             var currentTimer = All(); | ||||
|  | ||||
|             foreach (var timer in _timerJobs) | ||||
|             { | ||||
|                 var timerProviderLocal = timer; | ||||
|                 if (!currentTimer.Exists(c => c.TypeName == timerProviderLocal.GetType().ToString())) | ||||
|                 { | ||||
|                     var settings = new TimerSetting() | ||||
|                                        { | ||||
|                                            Enable = true, | ||||
|                                            TypeName = timer.GetType().ToString(), | ||||
|                                            Name = timerProviderLocal.Name, | ||||
|                                            Interval = timerProviderLocal.DefaultInterval, | ||||
|                                            LastExecution = DateTime.MinValue | ||||
|  | ||||
|                                        }; | ||||
|  | ||||
|                     SaveSettings(settings); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -23,13 +23,13 @@ namespace NzbDrone.Core.Providers | ||||
|         public virtual void Notify(string header, string message) | ||||
|         { | ||||
|             //Get time in seconds and convert to ms | ||||
|             var time = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", "3", true))*1000; | ||||
|             var time = Convert.ToInt32(_configProvider.GetValue("XbmcDisplayTime", "3", true)) * 1000; | ||||
|             var command = String.Format("ExecBuiltIn(Notification({0},{1},{2}))", header, message, time); | ||||
|  | ||||
|             if (Convert.ToBoolean(_configProvider.GetValue("XbmcNotificationImage", false, true))) | ||||
|             { | ||||
|                 //Todo: Get the actual port that NzbDrone is running on... | ||||
|                 var serverInfo = String.Format("http://{0}:{1}", ServerHelper.GetServerHostname(), "8989"); | ||||
|                 var serverInfo = String.Format("http://{0}:{1}", Environment.MachineName, "8989"); | ||||
|  | ||||
|                 var imageUrl = String.Format("{0}/Content/XbmcNotification.png", serverInfo); | ||||
|                 command = String.Format("ExecBuiltIn(Notification({0},{1},{2}, {3}))", header, message, time, imageUrl); | ||||
|   | ||||
| @@ -18,9 +18,9 @@ namespace NzbDrone.Core.Repository | ||||
|         public DayOfWeek? LastDiskSync { get; set; } | ||||
|  | ||||
|         [SubSonicToManyRelation] | ||||
|         public virtual List<Episode> Episodes { get; private set; } | ||||
|         public virtual List<Episode> Episodes { get; protected set; } | ||||
|  | ||||
|         [SubSonicToOneRelation(ThisClassContainsJoinKey = true)] | ||||
|         public virtual Series Series { get; private set; } | ||||
|         public virtual Series Series { get; protected set; } | ||||
|     } | ||||
| } | ||||
| @@ -45,15 +45,15 @@ namespace NzbDrone.Core.Repository | ||||
|         public DateTime? LastDiskSync { get; set; } | ||||
|  | ||||
|         [SubSonicToOneRelation(ThisClassContainsJoinKey = true, JoinKeyName = "QualityProfileId")] | ||||
|         public virtual QualityProfile QualityProfile { get; private set; } | ||||
|         public virtual QualityProfile QualityProfile { get; protected set; } | ||||
|  | ||||
|         [SubSonicToManyRelation] | ||||
|         public virtual List<Season> Seasons { get; private set; } | ||||
|         public virtual List<Season> Seasons { get; protected set; } | ||||
|  | ||||
|         [SubSonicToManyRelation] | ||||
|         public virtual List<Episode> Episodes { get; private set; } | ||||
|         public virtual List<Episode> Episodes { get; protected set; } | ||||
|  | ||||
|         [SubSonicToManyRelation] | ||||
|         public virtual List<EpisodeFile> EpisodeFiles { get; private set; } | ||||
|         public virtual List<EpisodeFile> EpisodeFiles { get; protected set; } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								NzbDrone.Core/Repository/TimerSetting.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								NzbDrone.Core/Repository/TimerSetting.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| using System; | ||||
| using SubSonic.SqlGeneration.Schema; | ||||
|  | ||||
| namespace NzbDrone.Core.Repository | ||||
| { | ||||
|     public class TimerSetting | ||||
|     { | ||||
|         [SubSonicPrimaryKey(true)] | ||||
|         public Int32 Id { get; set; } | ||||
|  | ||||
|         public Boolean Enable { get; set; } | ||||
|  | ||||
|         public String TypeName { get; set; } | ||||
|  | ||||
|         public String Name { get; set; } | ||||
|  | ||||
|         public Int32 Interval { get; set; } | ||||
|  | ||||
|         public DateTime LastExecution { get; set; } | ||||
|  | ||||
|         public Boolean Success { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -1,134 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Web; | ||||
| using System.Web.Mvc; | ||||
| using NzbDrone.Core.Providers; | ||||
| using NzbDrone.Core.Providers.Core; | ||||
| using NzbDrone.Web.Models; | ||||
|  | ||||
| namespace NzbDrone.Web.Controllers | ||||
| { | ||||
|     public class AddSeriesController : Controller | ||||
|     { | ||||
|         public IConfigProvider ConfigProvider { get; set; } | ||||
|         private readonly SyncProvider _syncProvider; | ||||
|         private readonly RootDirProvider _rootFolderProvider; | ||||
|         private readonly IConfigProvider _configProvider; | ||||
|         private readonly QualityProvider _qualityProvider; | ||||
|         private readonly TvDbProvider _tvDbProvider; | ||||
|         private readonly SeriesProvider _seriesProvider; | ||||
|  | ||||
|         public AddSeriesController(SyncProvider syncProvider, RootDirProvider rootFolderProvider, IConfigProvider configProvider, | ||||
|             QualityProvider qualityProvider, TvDbProvider tvDbProvider, SeriesProvider seriesProvider) | ||||
|         { | ||||
|             ConfigProvider = configProvider; | ||||
|             _syncProvider = syncProvider; | ||||
|             _rootFolderProvider = rootFolderProvider; | ||||
|             _configProvider = configProvider; | ||||
|             _qualityProvider = qualityProvider; | ||||
|             _tvDbProvider = tvDbProvider; | ||||
|             _seriesProvider = seriesProvider; | ||||
|         } | ||||
|  | ||||
|         [HttpPost] | ||||
|         public JsonResult ScanNewSeries() | ||||
|         { | ||||
|             _syncProvider.BeginUpdateNewSeries(); | ||||
|             return new JsonResult(); | ||||
|         } | ||||
|  | ||||
|         public ActionResult AddNew() | ||||
|         { | ||||
|             ViewData["RootDirs"] = _rootFolderProvider.GetAll(); | ||||
|             ViewData["DirSep"] = Path.DirectorySeparatorChar; | ||||
|  | ||||
|             var profiles = _qualityProvider.GetAllProfiles(); | ||||
|             var selectList = new SelectList(profiles, "QualityProfileId", "Name"); | ||||
|             var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); | ||||
|  | ||||
|             var model = new AddNewSeriesModel | ||||
|             { | ||||
|                 DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString(), | ||||
|                 RootDirectories = _rootFolderProvider.GetAll(), | ||||
|                 QualityProfileId = defaultQuality, | ||||
|                 QualitySelectList = selectList | ||||
|             }; | ||||
|  | ||||
|             return View(model); | ||||
|         } | ||||
|  | ||||
|         public ActionResult AddExisting() | ||||
|         { | ||||
|             var unmappedList = new List<String>(); | ||||
|  | ||||
|             var profiles = _qualityProvider.GetAllProfiles(); | ||||
|             var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); | ||||
|             var selectList = new SelectList(profiles, "QualityProfileId", "Name", defaultQuality); | ||||
|  | ||||
|             ViewData["qualities"] = selectList; | ||||
|  | ||||
|             foreach (var folder in _rootFolderProvider.GetAll()) | ||||
|             { | ||||
|                 unmappedList.AddRange(_syncProvider.GetUnmappedFolders(folder.Path)); | ||||
|             } | ||||
|  | ||||
|             return View(unmappedList); | ||||
|         } | ||||
|  | ||||
|         public ActionResult RenderPartial(string path) | ||||
|         { | ||||
|  | ||||
|             var suggestions = GetSuggestionList(new DirectoryInfo(path).Name); | ||||
|  | ||||
|             ViewData["guid"] = Guid.NewGuid(); | ||||
|             ViewData["path"] = path; | ||||
|             ViewData["javaPath"] = path.Replace(Path.DirectorySeparatorChar, '|').Replace(Path.VolumeSeparatorChar, '^'); | ||||
|  | ||||
|             var defaultQuality = _configProvider.DefaultQualityProfile; | ||||
|             var qualityProfiles = _qualityProvider.GetAllProfiles(); | ||||
|  | ||||
|             ViewData["quality"] = new SelectList( | ||||
|                 qualityProfiles, | ||||
|                 "QualityProfileId", | ||||
|                 "Name", | ||||
|                 defaultQuality); ; | ||||
|  | ||||
|             return PartialView("AddSeriesItem", suggestions); | ||||
|  | ||||
|         } | ||||
|  | ||||
|         public JsonResult AddSeries(string path, int seriesId, int qualityProfileId) | ||||
|         { | ||||
|             //Get TVDB Series Name | ||||
|             //Create new folder for series | ||||
|             //Add the new series to the Database | ||||
|  | ||||
|             _seriesProvider.AddSeries(path.Replace('|', Path.DirectorySeparatorChar).Replace('^', Path.VolumeSeparatorChar), seriesId, qualityProfileId); | ||||
|             ScanNewSeries(); | ||||
|             return new JsonResult() { Data = "ok" }; | ||||
|         } | ||||
|  | ||||
|         [HttpPost] | ||||
|         public ActionResult _textLookUp(string text, int? filterMode) | ||||
|         { | ||||
|             var suggestions = GetSuggestionList(text); | ||||
|  | ||||
|             return new JsonResult | ||||
|             { | ||||
|                 JsonRequestBehavior = JsonRequestBehavior.AllowGet, | ||||
|                 Data = suggestions | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         public SelectList GetSuggestionList(string searchString) | ||||
|         { | ||||
|             var dataVal = _tvDbProvider.SearchSeries(searchString); | ||||
|             //var bestResult = _tvDbProvider.GetBestMatch(dataVal.ToList(), searchString); | ||||
|  | ||||
|             return new SelectList(dataVal, "Id", "SeriesName", dataVal[0].Id); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -4,6 +4,7 @@ using System.IO; | ||||
| using System.Linq; | ||||
| using System.Web.Mvc; | ||||
| using NzbDrone.Core.Providers; | ||||
| using NzbDrone.Core.Providers.Timers; | ||||
| using NzbDrone.Core.Repository; | ||||
| using NzbDrone.Web.Models; | ||||
| using Telerik.Web.Mvc; | ||||
| @@ -19,28 +20,28 @@ namespace NzbDrone.Web.Controllers | ||||
|         private readonly QualityProvider _qualityProvider; | ||||
|         private readonly RenameProvider _renameProvider; | ||||
|         private readonly RootDirProvider _rootDirProvider; | ||||
|         private readonly RssSyncProvider _rssSyncProvider; | ||||
|         private readonly SeriesProvider _seriesProvider; | ||||
|         private readonly SyncProvider _syncProvider; | ||||
|         private readonly TvDbProvider _tvDbProvider; | ||||
|         private readonly TimerProvider _timerProvider; | ||||
|         // | ||||
|         // GET: /Series/ | ||||
|  | ||||
|         public SeriesController(SyncProvider syncProvider, SeriesProvider seriesProvider, | ||||
|                                 EpisodeProvider episodeProvider, RssSyncProvider rssSyncProvider, | ||||
|                                 EpisodeProvider episodeProvider, | ||||
|                                 QualityProvider qualityProvider, MediaFileProvider mediaFileProvider, | ||||
|                                 RenameProvider renameProvider, RootDirProvider rootDirProvider, | ||||
|                                 TvDbProvider tvDbProvider) | ||||
|                                 TvDbProvider tvDbProvider, TimerProvider timerProvider) | ||||
|         { | ||||
|             _seriesProvider = seriesProvider; | ||||
|             _episodeProvider = episodeProvider; | ||||
|             _syncProvider = syncProvider; | ||||
|             _rssSyncProvider = rssSyncProvider; | ||||
|             _qualityProvider = qualityProvider; | ||||
|             _mediaFileProvider = mediaFileProvider; | ||||
|             _renameProvider = renameProvider; | ||||
|             _rootDirProvider = rootDirProvider; | ||||
|             _tvDbProvider = tvDbProvider; | ||||
|             _timerProvider = timerProvider; | ||||
|         } | ||||
|  | ||||
|         public ActionResult Index() | ||||
| @@ -52,13 +53,13 @@ namespace NzbDrone.Web.Controllers | ||||
|  | ||||
|         public ActionResult RssSync() | ||||
|         { | ||||
|             _rssSyncProvider.Begin(); | ||||
|             _timerProvider.ForceExecute(typeof(RssSyncTimer)); | ||||
|             return RedirectToAction("Index"); | ||||
|         } | ||||
|  | ||||
|         public ActionResult UnMapped(string path) | ||||
|         { | ||||
|             return View(_syncProvider.GetUnmappedFolders(path).Select(c => new MappingModel {Id = 1, Path = c}).ToList()); | ||||
|             return View(_syncProvider.GetUnmappedFolders(path).Select(c => new MappingModel { Id = 1, Path = c }).ToList()); | ||||
|         } | ||||
|  | ||||
|         public ActionResult LoadEpisodes(int seriesId) | ||||
| @@ -121,7 +122,7 @@ namespace NzbDrone.Web.Controllers | ||||
|                     //We still want to show this series as unmapped, but we don't know what it will be when mapped | ||||
|                     //Todo: Provide the user with a way to manually map a folder to a TvDb series (or make them rename the folder...) | ||||
|                     if (tvDbSeries == null) | ||||
|                         tvDbSeries = new TvdbSeries {Id = 0, SeriesName = String.Empty}; | ||||
|                         tvDbSeries = new TvdbSeries { Id = 0, SeriesName = String.Empty }; | ||||
|  | ||||
|                     unmappedList.Add(new AddExistingSeriesModel | ||||
|                                          { | ||||
| @@ -263,7 +264,7 @@ namespace NzbDrone.Web.Controllers | ||||
|             var series = _seriesProvider.GetSeries(seriesId); | ||||
|             _mediaFileProvider.Scan(series); | ||||
|  | ||||
|             return RedirectToAction("Details", new {seriesId}); | ||||
|             return RedirectToAction("Details", new { seriesId }); | ||||
|         } | ||||
|  | ||||
|         public ActionResult RenameAll() | ||||
| @@ -275,7 +276,7 @@ namespace NzbDrone.Web.Controllers | ||||
|         public ActionResult RenameSeries(int seriesId) | ||||
|         { | ||||
|             _renameProvider.RenameSeries(seriesId); | ||||
|             return RedirectToAction("Details", new {seriesId}); | ||||
|             return RedirectToAction("Details", new { seriesId }); | ||||
|         } | ||||
|  | ||||
|         public ActionResult RenameSeason(int seasonId) | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| using System.Web.Mvc; | ||||
| using System; | ||||
| using System.Web.Mvc; | ||||
| using NzbDrone.Core.Providers; | ||||
| using NzbDrone.Core.Providers.Timers; | ||||
|  | ||||
| namespace NzbDrone.Web.Controllers | ||||
| { | ||||
| @@ -20,7 +22,7 @@ namespace NzbDrone.Web.Controllers | ||||
|         [ChildActionOnly] | ||||
|         public ActionResult Footer() | ||||
|         { | ||||
|             ViewData["RssTimer"] = _timerProvider.NextRssSyncTime().ToString("yyyyMMddHHmmss"); | ||||
|             ViewData["RssTimer"] = DateTime.Now.ToString("yyyyMMddHHmmss"); | ||||
|             //ViewData["RssTimer"] = DateTime.Now.AddMinutes(61).AddSeconds(10).ToString("yyyyMMddHHmmss"); | ||||
|             return PartialView(); | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user