display news on dashboard home page

This commit is contained in:
Luke Pulverenti 2014-01-18 16:52:01 -05:00
parent 5ca7d63556
commit 7f51148130
13 changed files with 257 additions and 1 deletions

View File

@ -93,6 +93,7 @@
<Compile Include="LiveTv\LiveTvService.cs" /> <Compile Include="LiveTv\LiveTvService.cs" />
<Compile Include="LocalizationService.cs" /> <Compile Include="LocalizationService.cs" />
<Compile Include="MoviesService.cs" /> <Compile Include="MoviesService.cs" />
<Compile Include="NewsService.cs" />
<Compile Include="NotificationsService.cs" /> <Compile Include="NotificationsService.cs" />
<Compile Include="PackageReviewService.cs" /> <Compile Include="PackageReviewService.cs" />
<Compile Include="PackageService.cs" /> <Compile Include="PackageService.cs" />

View File

@ -0,0 +1,48 @@
using MediaBrowser.Controller.News;
using MediaBrowser.Model.News;
using MediaBrowser.Model.Querying;
using ServiceStack;
namespace MediaBrowser.Api
{
[Route("/News/Product", "GET")]
[Api(Description = "Gets search hints based on a search term")]
public class GetProductNews : IReturn<QueryResult<NewsItem>>
{
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
/// <value>The start index.</value>
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get; set; }
/// <summary>
/// The maximum number of items to return
/// </summary>
/// <value>The limit.</value>
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Limit { get; set; }
}
public class NewsService : BaseApiService
{
private readonly INewsService _newsService;
public NewsService(INewsService newsService)
{
_newsService = newsService;
}
public object Get(GetProductNews request)
{
var result = _newsService.GetProductNews(new NewsQuery
{
StartIndex = request.StartIndex,
Limit = request.Limit
}).Result;
return ToOptimizedResult(result);
}
}
}

View File

@ -136,6 +136,7 @@
<Compile Include="Net\IHttpResultFactory.cs" /> <Compile Include="Net\IHttpResultFactory.cs" />
<Compile Include="Net\IHttpServer.cs" /> <Compile Include="Net\IHttpServer.cs" />
<Compile Include="Net\IRestfulService.cs" /> <Compile Include="Net\IRestfulService.cs" />
<Compile Include="News\INewsService.cs" />
<Compile Include="Notifications\INotificationsRepository.cs" /> <Compile Include="Notifications\INotificationsRepository.cs" />
<Compile Include="Notifications\NotificationUpdateEventArgs.cs" /> <Compile Include="Notifications\NotificationUpdateEventArgs.cs" />
<Compile Include="Persistence\MediaStreamQuery.cs" /> <Compile Include="Persistence\MediaStreamQuery.cs" />

View File

@ -0,0 +1,19 @@
using MediaBrowser.Model.News;
using MediaBrowser.Model.Querying;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.News
{
/// <summary>
/// Interface INewsFeed
/// </summary>
public interface INewsService
{
/// <summary>
/// Gets the product news.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>IEnumerable{NewsItem}.</returns>
Task<QueryResult<NewsItem>> GetProductNews(NewsQuery query);
}
}

View File

@ -290,6 +290,9 @@
<Compile Include="..\MediaBrowser.Model\Net\WebSocketState.cs"> <Compile Include="..\MediaBrowser.Model\Net\WebSocketState.cs">
<Link>Net\WebSocketState.cs</Link> <Link>Net\WebSocketState.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\News\NewsItem.cs">
<Link>News\NewsItem.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Notifications\Notification.cs"> <Compile Include="..\MediaBrowser.Model\Notifications\Notification.cs">
<Link>Notifications\Notification.cs</Link> <Link>Notifications\Notification.cs</Link>
</Compile> </Compile>

View File

@ -277,6 +277,9 @@
<Compile Include="..\MediaBrowser.Model\Net\WebSocketState.cs"> <Compile Include="..\MediaBrowser.Model\Net\WebSocketState.cs">
<Link>Net\WebSocketState.cs</Link> <Link>Net\WebSocketState.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\News\NewsItem.cs">
<Link>News\NewsItem.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\Notifications\Notification.cs"> <Compile Include="..\MediaBrowser.Model\Notifications\Notification.cs">
<Link>Notifications\Notification.cs</Link> <Link>Notifications\Notification.cs</Link>
</Compile> </Compile>

View File

@ -80,6 +80,7 @@
<Compile Include="LiveTv\RecordingStatus.cs" /> <Compile Include="LiveTv\RecordingStatus.cs" />
<Compile Include="LiveTv\SeriesTimerInfoDto.cs" /> <Compile Include="LiveTv\SeriesTimerInfoDto.cs" />
<Compile Include="LiveTv\TimerInfoDto.cs" /> <Compile Include="LiveTv\TimerInfoDto.cs" />
<Compile Include="News\NewsItem.cs" />
<Compile Include="Providers\ImageProviderInfo.cs" /> <Compile Include="Providers\ImageProviderInfo.cs" />
<Compile Include="Providers\RemoteImageInfo.cs" /> <Compile Include="Providers\RemoteImageInfo.cs" />
<Compile Include="Dto\StudioDto.cs" /> <Compile Include="Dto\StudioDto.cs" />

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace MediaBrowser.Model.News
{
public class NewsChannel
{
public string Title { get; set; }
public string Link { get; set; }
public string Description { get; set; }
public List<NewsItem> Items { get; set; }
}
public class NewsItem
{
public string Title { get; set; }
public string Link { get; set; }
public string Description { get; set; }
public string Guid { get; set; }
public DateTime Date { get; set; }
}
public class NewsQuery
{
public int? StartIndex { get; set; }
public int? Limit { get; set; }
}
}

View File

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

View File

@ -0,0 +1,132 @@
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;
namespace MediaBrowser.Server.Implementations.News
{
public class NewsService : INewsService
{
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
public NewsService(IApplicationPaths appPaths, IFileSystem fileSystem, IHttpClient httpClient)
{
_appPaths = appPaths;
_fileSystem = fileSystem;
_httpClient = httpClient;
}
public async Task<QueryResult<NewsItem>> GetProductNews(NewsQuery query)
{
var path = Path.Combine(_appPaths.CachePath, "news.xml");
await EnsureNewsFile(path).ConfigureAwait(false);
var items = GetNewsItems(path);
var itemsArray = items.ToArray();
var count = itemsArray.Length;
if (query.StartIndex.HasValue)
{
itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
}
if (query.Limit.HasValue)
{
itemsArray = itemsArray.Take(query.Limit.Value).ToArray();
}
return new QueryResult<NewsItem>
{
Items = itemsArray,
TotalRecordCount = count
};
}
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 > 24)
{
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);
}
}
}
}
}
}

View File

@ -19,6 +19,7 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.MediaInfo; using MediaBrowser.Controller.MediaInfo;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.News;
using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Notifications;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Plugins;
@ -283,6 +284,10 @@ namespace MediaBrowser.ServerApplication
DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor); DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);
RegisterSingleInstance(DtoService); RegisterSingleInstance(DtoService);
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, FileSystemManager, HttpClient);
RegisterSingleInstance<INewsService>(newsService);
progress.Report(15); progress.Report(15);
var innerProgress = new ActionableProgress<double>(); var innerProgress = new ActionableProgress<double>();

View File

@ -197,6 +197,19 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
return webSocket && (webSocket.readyState === WebSocket.OPEN || webSocket.readyState === WebSocket.CONNECTING); return webSocket && (webSocket.readyState === WebSocket.OPEN || webSocket.readyState === WebSocket.CONNECTING);
}; };
self.getProductNews = function (options) {
options = options || {};
var url = self.getUrl("News/Product", options);
return self.ajax({
type: "GET",
url: url,
dataType: "json"
});
};
/** /**
* Gets an item from the server * Gets an item from the server
* Omit itemId to get the root folder. * Omit itemId to get the root folder.

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.237" targetFramework="net45" /> <package id="MediaBrowser.ApiClient.Javascript" version="3.0.238" targetFramework="net45" />
</packages> </packages>