display news on dashboard home page
This commit is contained in:
parent
5ca7d63556
commit
7f51148130
|
@ -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" />
|
||||||
|
|
48
MediaBrowser.Api/NewsService.cs
Normal file
48
MediaBrowser.Api/NewsService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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" />
|
||||||
|
|
19
MediaBrowser.Controller/News/INewsService.cs
Normal file
19
MediaBrowser.Controller/News/INewsService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
29
MediaBrowser.Model/News/NewsItem.cs
Normal file
29
MediaBrowser.Model/News/NewsItem.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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" />
|
||||||
|
|
132
MediaBrowser.Server.Implementations/News/NewsService.cs
Normal file
132
MediaBrowser.Server.Implementations/News/NewsService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue
Block a user