2
0
Luke Pulverenti 11 жил өмнө
parent
commit
d2cae40128

+ 2 - 2
MediaBrowser.Api/NewsService.cs

@@ -6,7 +6,7 @@ using ServiceStack;
 namespace MediaBrowser.Api
 {
     [Route("/News/Product", "GET")]
-    [Api(Description = "Gets search hints based on a search term")]
+    [Api(Description = "Gets the latest product news.")]
     public class GetProductNews : IReturn<QueryResult<NewsItem>>
     {
         /// <summary>
@@ -40,7 +40,7 @@ namespace MediaBrowser.Api
                  StartIndex = request.StartIndex,
                  Limit = request.Limit
 
-            }).Result;
+            });
 
             return ToOptimizedResult(result);
         }

+ 2 - 3
MediaBrowser.Controller/News/INewsService.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Model.News;
 using MediaBrowser.Model.Querying;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.News
 {
@@ -13,7 +12,7 @@ namespace MediaBrowser.Controller.News
         /// Gets the product news.
         /// </summary>
         /// <param name="query">The query.</param>
-        /// <returns>IEnumerable{NewsItem}.</returns>
-        Task<QueryResult<NewsItem>> GetProductNews(NewsQuery query);
+        /// <returns>QueryResult{NewsItem}.</returns>
+        QueryResult<NewsItem> GetProductNews(NewsQuery query);
     }
 }

+ 1 - 0
MediaBrowser.Model/News/NewsItem.cs

@@ -16,6 +16,7 @@ namespace MediaBrowser.Model.News
         public string Title { get; set; }
         public string Link { get; set; }
         public string Description { get; set; }
+        public string DescriptionHtml { get; set; }
         public string Guid { get; set; }
         public DateTime Date { get; set; }
     }

+ 25 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -229,6 +229,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 return result;
             }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error getting recording stream", ex);
+
+                throw;
+            }
             finally
             {
                 _liveStreamSemaphore.Release();
@@ -245,6 +251,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 var channel = GetInternalChannel(id);
 
+                _logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ChannelInfo.Id);
+
                 var result = await service.GetChannelStream(channel.ChannelInfo.Id, cancellationToken).ConfigureAwait(false);
 
                 if (!string.IsNullOrEmpty(result.Id))
@@ -254,6 +262,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 return result;
             }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error getting channel stream", ex);
+
+                throw;
+            }
             finally
             {
                 _liveStreamSemaphore.Release();
@@ -1261,9 +1275,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
+            var service = ActiveService;
+
+            _logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id);
+
             try
             {
-                await ActiveService.CloseLiveStream(id, cancellationToken).ConfigureAwait(false);
+                await service.CloseLiveStream(id, cancellationToken).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error closing live stream", ex);
+
+                throw;
             }
             finally
             {

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

@@ -173,6 +173,7 @@
     <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="MediaEncoder\MediaEncoder.cs" />
+    <Compile Include="News\NewsEntryPoint.cs" />
     <Compile Include="News\NewsService.cs" />
     <Compile Include="Persistence\SqliteChapterRepository.cs" />
     <Compile Include="Persistence\SqliteExtensions.cs" />

+ 127 - 0
MediaBrowser.Server.Implementations/News/NewsEntryPoint.cs

@@ -0,0 +1,127 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.News;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace MediaBrowser.Server.Implementations.News
+{
+    public class NewsEntryPoint : IServerEntryPoint
+    {
+        private Timer _timer;
+        private readonly IHttpClient _httpClient;
+        private readonly IApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
+        private readonly ILogger _logger;
+        private readonly IJsonSerializer _json;
+
+        private readonly TimeSpan _frequency = TimeSpan.FromHours(24);
+
+        public NewsEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IJsonSerializer json)
+        {
+            _httpClient = httpClient;
+            _appPaths = appPaths;
+            _fileSystem = fileSystem;
+            _logger = logger;
+            _json = json;
+        }
+
+        public void Run()
+        {
+            _timer = new Timer(OnTimerFired, null, TimeSpan.FromMilliseconds(500), _frequency);
+        }
+
+        /// <summary>
+        /// Called when [timer fired].
+        /// </summary>
+        /// <param name="state">The state.</param>
+        private async void OnTimerFired(object state)
+        {
+            var path = Path.Combine(_appPaths.CachePath, "news.json");
+
+            try
+            {
+                await DownloadNews(path).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error downloading news", ex);
+            }
+        }
+
+        private async Task DownloadNews(string path)
+        {
+            var requestOptions = new HttpRequestOptions
+            {
+                Url = "http://mediabrowser3.com/community/index.php?/blog/rss/1-media-browser-developers-blog",
+                Progress = new Progress<double>()
+            };
+
+            using (var stream = await _httpClient.Get(requestOptions).ConfigureAwait(false))
+            {
+                var doc = new XmlDocument();
+                doc.Load(stream);
+
+                var news = ParseRssItems(doc).ToList();
+
+                _json.SerializeToFile(news, path);
+            }
+        }
+
+        private IEnumerable<NewsItem> ParseRssItems(XmlDocument xmlDoc)
+        {
+            var nodes = xmlDoc.SelectNodes("rss/channel/item");
+
+            if (nodes != null)
+            {
+                foreach (XmlNode node in nodes)
+                {
+                    var newsItem = new NewsItem();
+
+                    newsItem.Title = ParseDocElements(node, "title");
+
+                    newsItem.DescriptionHtml = ParseDocElements(node, "description");
+                    newsItem.Description = newsItem.DescriptionHtml.StripHtml();
+
+                    newsItem.Link = ParseDocElements(node, "link");
+
+                    var date = ParseDocElements(node, "pubDate");
+                    DateTime parsedDate;
+
+                    if (DateTime.TryParse(date, out parsedDate))
+                    {
+                        newsItem.Date = parsedDate;
+                    }
+
+                    yield return newsItem;
+                }
+            }
+        }
+
+        private string ParseDocElements(XmlNode parent, string xPath)
+        {
+            var node = parent.SelectSingleNode(xPath);
+
+            return node != null ? node.InnerText : string.Empty;
+        }
+
+        public void Dispose()
+        {
+            if (_timer != null)
+            {
+                _timer.Dispose();
+                _timer = null;
+            }
+        }
+    }
+}

+ 23 - 85
MediaBrowser.Server.Implementations/News/NewsService.cs

@@ -1,38 +1,46 @@
 using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.News;
 using MediaBrowser.Model.News;
 using MediaBrowser.Model.Querying;
-using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Threading.Tasks;
-using System.Xml;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Server.Implementations.News
 {
     public class NewsService : INewsService
     {
         private readonly IApplicationPaths _appPaths;
-        private readonly IFileSystem _fileSystem;
-        private readonly IHttpClient _httpClient;
+        private readonly IJsonSerializer _json;
 
-        public NewsService(IApplicationPaths appPaths, IFileSystem fileSystem, IHttpClient httpClient)
+        public NewsService(IApplicationPaths appPaths, IJsonSerializer json)
         {
             _appPaths = appPaths;
-            _fileSystem = fileSystem;
-            _httpClient = httpClient;
+            _json = json;
         }
 
-        public async Task<QueryResult<NewsItem>> GetProductNews(NewsQuery query)
+        public QueryResult<NewsItem> GetProductNews(NewsQuery query)
         {
-            var path = Path.Combine(_appPaths.CachePath, "news.xml");
+            try
+            {
+                return GetProductNewsInternal(query);
+            }
+            catch (FileNotFoundException)
+            {
+                // No biggie
+                return new QueryResult<NewsItem>
+                {
+                    Items = new NewsItem[] { }
+                };
+            }
+        }
 
-            await EnsureNewsFile(path).ConfigureAwait(false);
+        private QueryResult<NewsItem> GetProductNewsInternal(NewsQuery query)
+        {
+            var path = Path.Combine(_appPaths.CachePath, "news.json");
 
-            var items = GetNewsItems(path);
+            var items = GetNewsItems(path).OrderByDescending(i => i.Date);
 
             var itemsArray = items.ToArray();
             var count = itemsArray.Length;
@@ -56,77 +64,7 @@ namespace MediaBrowser.Server.Implementations.News
 
         private IEnumerable<NewsItem> GetNewsItems(string path)
         {
-            var xmlDoc = new XmlDocument();
-
-            xmlDoc.Load(path);
-
-            return ParseRssItems(xmlDoc);
-        }
-
-        private IEnumerable<NewsItem> ParseRssItems(XmlDocument xmlDoc)
-        {
-            var nodes = xmlDoc.SelectNodes("rss/channel/item");
-
-            if (nodes == null)
-            {
-                yield return null;
-            }
-
-            foreach (XmlNode node in nodes)
-            {
-                var newsItem = new NewsItem();
-
-                newsItem.Title = ParseDocElements(node, "title");
-
-                newsItem.Description = ParseDocElements(node, "description");
-
-                newsItem.Link = ParseDocElements(node, "link");
-
-                var date = ParseDocElements(node, "pubDate");
-                DateTime parsedDate;
-
-                if (DateTime.TryParse(date, out parsedDate))
-                {
-                    newsItem.Date = parsedDate;
-                }
-
-                yield return newsItem;
-            }
-        }
-
-        private string ParseDocElements(XmlNode parent, string xPath)
-        {
-            var node = parent.SelectSingleNode(xPath);
-
-            return node != null ? node.InnerText : "Unresolvable";
-        }
-
-
-        /// <summary>
-        /// Ensures the news file.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <returns>Task.</returns>
-        private async Task EnsureNewsFile(string path)
-        {
-            var info = _fileSystem.GetFileSystemInfo(path);
-
-            if (!info.Exists || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(info)).TotalHours > 12)
-            {
-                var requestOptions = new HttpRequestOptions
-                {
-                    Url = "http://mediabrowser3.com/community/index.php?/blog/rss/1-media-browser-developers-blog",
-                    Progress = new Progress<double>()
-                };
-
-                using (var stream = await _httpClient.Get(requestOptions).ConfigureAwait(false))
-                {
-                    using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
-                    {
-                        await stream.CopyToAsync(fileStream).ConfigureAwait(false);
-                    }
-                }
-            }
+            return _json.DeserializeFromFile<List<NewsItem>>(path);
         }
     }
 }

+ 1 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -285,7 +285,7 @@ namespace MediaBrowser.ServerApplication
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);
             RegisterSingleInstance(DtoService);
 
-            var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, FileSystemManager, HttpClient);
+            var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             RegisterSingleInstance<INewsService>(newsService);
 
             progress.Report(15);