diff options
| -rw-r--r-- | MediaBrowser.Api/Images/ImageService.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.Api/ItemUpdateService.cs | 41 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/Channel.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Model/LiveTv/ChannelInfoDto.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Providers/LiveTv/ChannelProviderFromXml.cs | 104 | ||||
| -rw-r--r-- | MediaBrowser.Providers/MediaBrowser.Providers.csproj | 2 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Savers/ChannelXmlSaver.cs | 74 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/Api/DashboardService.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/ApiClient.js | 55 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 8 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/packages.config | 2 |
12 files changed, 315 insertions, 10 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 5234dda18..e5603967b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -38,6 +38,18 @@ namespace MediaBrowser.Api.Images public string Id { get; set; } } + [Route("/LiveTv/Channels/{Id}/Images", "GET")] + [Api(Description = "Gets information about an item's images")] + public class GetChannelImageInfos : IReturn<List<ImageInfo>> + { + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value>The id.</value> + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + [Route("/Artists/{Name}/Images", "GET")] [Route("/Genres/{Name}/Images", "GET")] [Route("/GameGenres/{Name}/Images", "GET")] @@ -386,6 +398,15 @@ namespace MediaBrowser.Api.Images return ToOptimizedResult(result); } + public object Get(GetChannelImageInfos request) + { + var item = _liveTv.GetChannel(request.Id); + + var result = GetItemImageInfos(item); + + return ToOptimizedResult(result); + } + public object Get(GetItemByNameImageInfos request) { var result = GetItemByNameImageInfos(request); diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 10149906c..95876f1a5 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using ServiceStack.ServiceHost; @@ -13,6 +14,14 @@ using System.Threading.Tasks; namespace MediaBrowser.Api { + [Route("/LiveTv/Channels/{ChannelId}", "POST")] + [Api(("Updates an item"))] + public class UpdateChannel : BaseItemDto, IReturnVoid + { + [ApiMember(Name = "ChannelId", Description = "The id of the channel", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string ChannelId { get; set; } + } + [Route("/Items/{ItemId}", "POST")] [Api(("Updates an item"))] public class UpdateItem : BaseItemDto, IReturnVoid @@ -73,11 +82,13 @@ namespace MediaBrowser.Api { private readonly ILibraryManager _libraryManager; private readonly IDtoService _dtoService; + private readonly ILiveTvManager _liveTv; - public ItemUpdateService(ILibraryManager libraryManager, IDtoService dtoService) + public ItemUpdateService(ILibraryManager libraryManager, IDtoService dtoService, ILiveTvManager liveTv) { _libraryManager = libraryManager; _dtoService = dtoService; + _liveTv = liveTv; } public void Post(UpdateItem request) @@ -87,6 +98,13 @@ namespace MediaBrowser.Api Task.WaitAll(task); } + public void Post(UpdateChannel request) + { + var task = UpdateItem(request); + + Task.WaitAll(task); + } + private Task UpdateItem(UpdateItem request) { var item = _dtoService.GetItemByDtoId(request.ItemId); @@ -112,6 +130,15 @@ namespace MediaBrowser.Api await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } + private async Task UpdateItem(UpdateChannel request) + { + var item = _liveTv.GetChannel(request.Id); + + UpdateItem(request, item); + + await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + } + public void Post(UpdateArtist request) { var task = UpdateItem(request); @@ -226,8 +253,16 @@ namespace MediaBrowser.Api item.Overview = request.Overview; item.Genres = request.Genres; item.Tags = request.Tags; - item.Studios = request.Studios.Select(x => x.Name).ToList(); - item.People = request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList(); + + if (request.Studios != null) + { + item.Studios = request.Studios.Select(x => x.Name).ToList(); + } + + if (request.People != null) + { + item.People = request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList(); + } if (request.DateCreated.HasValue) { diff --git a/MediaBrowser.Controller/LiveTv/Channel.cs b/MediaBrowser.Controller/LiveTv/Channel.cs index 26245e6fb..94d76971c 100644 --- a/MediaBrowser.Controller/LiveTv/Channel.cs +++ b/MediaBrowser.Controller/LiveTv/Channel.cs @@ -61,5 +61,13 @@ namespace MediaBrowser.Controller.LiveTv return number.ToString("000-") + (Name ?? string.Empty); } + + public override string MediaType + { + get + { + return ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video; + } + } } } diff --git a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs index 8e4c95870..fe242b66c 100644 --- a/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/ChannelInfoDto.cs @@ -54,5 +54,11 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value>The type.</value> public string Type { get; set; } + + /// <summary> + /// Gets or sets the type of the media. + /// </summary> + /// <value>The type of the media.</value> + public string MediaType { get; set; } } } diff --git a/MediaBrowser.Providers/LiveTv/ChannelProviderFromXml.cs b/MediaBrowser.Providers/LiveTv/ChannelProviderFromXml.cs new file mode 100644 index 000000000..b166750b5 --- /dev/null +++ b/MediaBrowser.Providers/LiveTv/ChannelProviderFromXml.cs @@ -0,0 +1,104 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.LiveTv +{ + class ChannelProviderFromXml : BaseMetadataProvider + { + internal static ChannelProviderFromXml Current { get; private set; } + private readonly IFileSystem _fileSystem; + + public ChannelProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) + : base(logManager, configurationManager) + { + _fileSystem = fileSystem; + Current = this; + } + + /// <summary> + /// Supportses the specified item. + /// </summary> + /// <param name="item">The item.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + public override bool Supports(BaseItem item) + { + return item is Channel; + } + + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Second; } + } + + private const string XmlFileName = "channel.xml"; + protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) + { + var xml = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); + + if (xml == null) + { + return false; + } + + return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed; + } + + /// <summary> + /// Fetches metadata and returns true or false indicating if any work that requires persistence was done + /// </summary> + /// <param name="item">The item.</param> + /// <param name="force">if set to <c>true</c> [force].</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{System.Boolean}.</returns> + public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) + { + return Fetch(item, cancellationToken); + } + + /// <summary> + /// Fetches the specified item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); + + if (metadataFile != null) + { + var path = metadataFile.FullName; + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + new BaseItemXmlParser<Channel>(Logger).Fetch((Channel)item, path, cancellationToken); + } + finally + { + XmlParsingResourcePool.Release(); + } + + SetLastRefreshed(item, DateTime.UtcNow); + return true; + } + + return false; + } + } +} diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 46bce4909..83e0246c5 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -55,6 +55,7 @@ <Compile Include="Games\GameSystemProviderFromXml.cs" /> <Compile Include="ImageFromMediaLocationProvider.cs" /> <Compile Include="ImagesByNameProvider.cs" /> + <Compile Include="LiveTv\ChannelProviderFromXml.cs" /> <Compile Include="MediaInfo\AudioImageProvider.cs" /> <Compile Include="MediaInfo\BaseFFProbeProvider.cs" /> <Compile Include="MediaInfo\FFProbeAudioInfoProvider.cs" /> @@ -100,6 +101,7 @@ <Compile Include="Savers\AlbumXmlSaver.cs" /> <Compile Include="Savers\ArtistXmlSaver.cs" /> <Compile Include="Savers\BoxSetXmlSaver.cs" /> + <Compile Include="Savers\ChannelXmlSaver.cs" /> <Compile Include="Savers\EpisodeXmlSaver.cs" /> <Compile Include="Savers\FolderXmlSaver.cs" /> <Compile Include="Savers\GameSystemXmlSaver.cs" /> diff --git a/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs b/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs new file mode 100644 index 000000000..c6ac220a9 --- /dev/null +++ b/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs @@ -0,0 +1,74 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Providers.LiveTv; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace MediaBrowser.Providers.Savers +{ + /// <summary> + /// Class PersonXmlSaver + /// </summary> + public class ChannelXmlSaver : IMetadataSaver + { + /// <summary> + /// Determines whether [is enabled for] [the specified item]. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="updateType">Type of the update.</param> + /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns> + public bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) + { + var wasMetadataEdited = (updateType & ItemUpdateType.MetadataEdit) == ItemUpdateType.MetadataEdit; + var wasMetadataDownloaded = (updateType & ItemUpdateType.MetadataDownload) == ItemUpdateType.MetadataDownload; + + // If new metadata has been downloaded or metadata was manually edited, proceed + if ((wasMetadataEdited || wasMetadataDownloaded)) + { + return item is Channel; + } + + return false; + } + + /// <summary> + /// Saves the specified item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + public void Save(BaseItem item, CancellationToken cancellationToken) + { + var builder = new StringBuilder(); + + builder.Append("<Item>"); + + XmlSaverHelpers.AddCommonNodes(item, builder); + + builder.Append("</Item>"); + + var xmlFilePath = GetSavePath(item); + + XmlSaverHelpers.Save(builder, xmlFilePath, new List<string> + { + }); + + // Set last refreshed so that the provider doesn't trigger after the file save + ChannelProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); + } + + /// <summary> + /// Gets the save path. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + public string GetSavePath(BaseItem item) + { + return Path.Combine(item.Path, "channel.xml"); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 8ea4ff1d3..973fa5409 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -74,7 +74,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv Number = info.ChannelNumber, PrimaryImageTag = GetLogoImageTag(info), Type = info.GetType().Name, - Id = info.Id.ToString("N") + Id = info.Id.ToString("N"), + MediaType = info.MediaType }; } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 681479eb7..2b74eebb0 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -479,6 +479,7 @@ namespace MediaBrowser.WebDashboard.Api "itemgallery.js", "itemlistpage.js", "librarysettings.js", + "livetvchannel.js", "livetvchannels.js", "livetvguide.js", "livetvrecordings.js", diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 387a84970..f2c098723 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -389,6 +389,21 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.getLiveTvChannel = function (id) { + + if (!id) { + throw new Error("null id"); + } + + var url = self.getUrl("/LiveTv/Channels/" + id); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + self.getLiveTvChannels = function (options) { var url = self.getUrl("/LiveTv/Channels", options || {}); @@ -1236,7 +1251,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi if (itemType == "Artist") { url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images"); - } else if (itemType == "Genre") { + } + else if (itemType == "Channel") { + url = self.getUrl("LiveTv/Channels/" + itemId + "/Images"); + } + else if (itemType == "Genre") { url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images"); } else if (itemType == "GameGenre") { url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images"); @@ -1292,7 +1311,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi if (itemType == "Artist") { url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options); - } else if (itemType == "Genre") { + } + else if (itemType == "Channel") { + url = self.getUrl("LiveTv/Channels/" + itemId + "/Images/" + imageType + "/" + imageIndex + "/Index", options); + } + else if (itemType == "Genre") { url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options); } else if (itemType == "GameGenre") { url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options); @@ -1322,7 +1345,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi if (itemType == "Artist") { url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images"); - } else if (itemType == "Genre") { + } + else if (itemType == "Channel") { + url = self.getUrl("LiveTv/Channels/" + itemId + "/Images"); + } + else if (itemType == "Genre") { url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images"); } else if (itemType == "GameGenre") { url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images"); @@ -1455,7 +1482,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi if (itemType == "Artist") { url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images"); - } else if (itemType == "Genre") { + } + else if (itemType == "Channel") { + url = self.getUrl("LiveTv/Channels/" + itemId + "/Images"); + } + else if (itemType == "Genre") { url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images"); } else if (itemType == "GameGenre") { url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images"); @@ -2318,6 +2349,22 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.updateLiveTvChannel = function (item) { + + if (!item) { + throw new Error("null item"); + } + + var url = self.getUrl("LiveTv/Channels/" + item.Id); + + return self.ajax({ + type: "POST", + url: url, + data: JSON.stringify(item), + contentType: "application/json" + }); + }; + self.updateArtist = function (item) { if (!item) { diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 135c15072..54e70cb9a 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -80,6 +80,9 @@ </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ApiClient.js" />
+ <Content Include="dashboard-ui\livetvchannel.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\musicalbumartists.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -344,6 +347,9 @@ <Content Include="dashboard-ui\livetvrecordings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\livetvchannel.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\musicalbumartists.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -1197,7 +1203,7 @@ </Content>
</ItemGroup>
<ItemGroup>
- <None Include="packages.config" />
+ <EmbeddedResource Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 6e250aae3..75cba2864 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="MediaBrowser.ApiClient.Javascript" version="3.0.194" targetFramework="net45" /> + <package id="MediaBrowser.ApiClient.Javascript" version="3.0.198" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.62" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.62" targetFramework="net45" /> </packages>
\ No newline at end of file |
