diff options
31 files changed, 758 insertions, 48 deletions
diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs new file mode 100644 index 000000000..aa8fc9e52 --- /dev/null +++ b/MediaBrowser.Api/ChannelService.cs @@ -0,0 +1,43 @@ +using MediaBrowser.Controller.Channels; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; +using ServiceStack; +using System.Threading; + +namespace MediaBrowser.Api +{ + [Route("/Channels", "GET")] + [Api(("Gets available channels"))] + public class GetChannels : IReturn<QueryResult<BaseItemDto>> + { + public string UserId { get; set; } + + public int? StartIndex { get; set; } + + public int? Limit { get; set; } + } + + public class ChannelService : BaseApiService + { + private readonly IChannelManager _channelManager; + + public ChannelService(IChannelManager channelManager) + { + _channelManager = channelManager; + } + + public object Get(GetChannels request) + { + var result = _channelManager.GetChannels(new ChannelQuery + { + Limit = request.Limit, + StartIndex = request.StartIndex, + UserId = request.UserId, + + }, CancellationToken.None).Result; + + return ToOptimizedResult(result); + } + } +} diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index e19fbb967..38cf39b54 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,6 +66,7 @@ <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> + <Compile Include="ChannelService.cs" /> <Compile Include="Movies\CollectionService.cs" /> <Compile Include="Music\AlbumsService.cs" /> <Compile Include="AppThemeService.cs" /> diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs new file mode 100644 index 000000000..c9a70f2bc --- /dev/null +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -0,0 +1,9 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Channels +{ + public class Channel : BaseItem + { + public string OriginalChannelName { get; set; } + } +} diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs new file mode 100644 index 000000000..269a95456 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller.Entities.Audio; + +namespace MediaBrowser.Controller.Channels +{ + public class ChannelAudioItem : Audio, IChannelItem + { + public string ExternalId { get; set; } + + public ChannelItemType ChannelItemType { get; set; } + + public bool IsInfiniteStream { get; set; } + + public ChannelMediaContentType ContentType { get; set; } + + public string OriginalImageUrl { get; set; } + } +} diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index 496fbfbf4..f80ad8911 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -1,9 +1,11 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Entities; +using System; using System.Collections.Generic; namespace MediaBrowser.Controller.Channels { - public class ChannelItemInfo + public class ChannelItemInfo : IHasProviderIds { public string Name { get; set; } @@ -23,18 +25,21 @@ namespace MediaBrowser.Controller.Channels public long? RunTimeTicks { get; set; } - public bool IsInfinite { get; set; } + public bool IsInfiniteStream { get; set; } public string ImageUrl { get; set; } public ChannelMediaType MediaType { get; set; } public ChannelMediaContentType ContentType { get; set; } + + public Dictionary<string, string> ProviderIds { get; set; } public ChannelItemInfo() { Genres = new List<string>(); People = new List<PersonInfo>(); + ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); } } diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs new file mode 100644 index 000000000..baa4c2a17 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Channels +{ + public class ChannelVideoItem : Video, IChannelItem + { + public string ExternalId { get; set; } + + public ChannelItemType ChannelItemType { get; set; } + + public bool IsInfiniteStream { get; set; } + + public ChannelMediaContentType ContentType { get; set; } + + public string OriginalImageUrl { get; set; } + } +} diff --git a/MediaBrowser.Controller/Channels/IChannel.cs b/MediaBrowser.Controller/Channels/IChannel.cs index ba1bd4083..956eb67e8 100644 --- a/MediaBrowser.Controller/Channels/IChannel.cs +++ b/MediaBrowser.Controller/Channels/IChannel.cs @@ -26,13 +26,20 @@ namespace MediaBrowser.Controller.Channels ChannelCapabilities GetCapabilities(); /// <summary> + /// Determines whether [is enabled for] [the specified user]. + /// </summary> + /// <param name="user">The user.</param> + /// <returns><c>true</c> if [is enabled for] [the specified user]; otherwise, <c>false</c>.</returns> + bool IsEnabledFor(User user); + + /// <summary> /// Searches the specified search term. /// </summary> - /// <param name="searchTerm">The search term.</param> + /// <param name="searchInfo">The search information.</param> /// <param name="user">The user.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{IEnumerable{ChannelItemInfo}}.</returns> - Task<IEnumerable<ChannelItemInfo>> Search(string searchTerm, User user, CancellationToken cancellationToken); + Task<IEnumerable<ChannelItemInfo>> Search(ChannelSearchInfo searchInfo, User user, CancellationToken cancellationToken); /// <summary> /// Gets the channel items. @@ -56,4 +63,9 @@ namespace MediaBrowser.Controller.Channels { public bool CanSearch { get; set; } } + + public class ChannelSearchInfo + { + public string SearchTerm { get; set; } + } } diff --git a/MediaBrowser.Controller/Channels/IChannelItem.cs b/MediaBrowser.Controller/Channels/IChannelItem.cs new file mode 100644 index 000000000..ffef532a9 --- /dev/null +++ b/MediaBrowser.Controller/Channels/IChannelItem.cs @@ -0,0 +1,17 @@ +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Channels +{ + public interface IChannelItem : IHasImages + { + string ExternalId { get; set; } + + ChannelItemType ChannelItemType { get; set; } + + bool IsInfiniteStream { get; set; } + + ChannelMediaContentType ContentType { get; set; } + + string OriginalImageUrl { get; set; } + } +} diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 561ab555b..b34e77415 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -1,12 +1,34 @@ -using System; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Querying; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller.Channels { public interface IChannelManager { + /// <summary> + /// Adds the parts. + /// </summary> + /// <param name="channels">The channels.</param> + void AddParts(IEnumerable<IChannel> channels); + + /// <summary> + /// Gets the channels. + /// </summary> + /// <param name="query">The query.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{QueryResult{BaseItemDto}}.</returns> + Task<QueryResult<BaseItemDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken); + + /// <summary> + /// Gets the channel items. + /// </summary> + /// <param name="query">The query.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task{QueryResult{BaseItemDto}}.</returns> + Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs index a3a615516..4ccba1106 100644 --- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs @@ -25,6 +25,21 @@ namespace MediaBrowser.Controller.Dlna /// <value>The name of the model.</value> public string ModelName { get; set; } /// <summary> + /// Gets or sets the model description. + /// </summary> + /// <value>The model description.</value> + public string ModelDescription { get; set; } + /// <summary> + /// Gets or sets the device description. + /// </summary> + /// <value>The device description.</value> + public string DeviceDescription { get; set; } + /// <summary> + /// Gets or sets the model URL. + /// </summary> + /// <value>The model URL.</value> + public string ModelUrl { get; set; } + /// <summary> /// Gets or sets the manufacturer. /// </summary> /// <value> diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index 119cfffd7..ca5929d13 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -33,6 +33,28 @@ namespace MediaBrowser.Controller.Dlna /// <value>The identification.</value> public DeviceIdentification Identification { get; set; } + public string FriendlyName { get; set; } + public string Manufacturer { get; set; } + public string ManufacturerUrl { get; set; } + public string ModelName { get; set; } + public string ModelDescription { get; set; } + public string ModelNumber { get; set; } + public string ModelUrl { get; set; } + /// <summary> + /// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace. + /// </summary> + public string XDlnaDoc { get; set; } + /// <summary> + /// Controls the content of the X_DLNACAP element in the urn:schemas-dlna-org:device-1-0 namespace. + /// </summary> + public string XDlnaCap { get; set; } + /// <summary> + /// Controls the content of the aggregationFlags element in the urn:schemas-sonycom:av. + /// </summary> + public string SonyAggregationFlags { get; set; } + + public string ProtocolInfo { get; set; } + public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs index 8c35b52a8..68e25e2f7 100644 --- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs @@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.Dlna } } + public string OrgPn { get; set; } public string MimeType { get; set; } public DlnaProfileType Type { get; set; } diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs index abc8868fb..3b0a513d1 100644 --- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs @@ -1,4 +1,5 @@ - +using System.Collections.Generic; + namespace MediaBrowser.Controller.Dlna { public class TranscodingProfile @@ -9,8 +10,28 @@ namespace MediaBrowser.Controller.Dlna public string MimeType { get; set; } + public string OrgPn { get; set; } + public string VideoCodec { get; set; } public string AudioCodec { get; set; } + + public List<TranscodingSetting> Settings { get; set; } + + public TranscodingProfile() + { + Settings = new List<TranscodingSetting>(); + } + } + + public class TranscodingSetting + { + public TranscodingSettingType Name { get; set; } + public string Value { get; set; } + } + + public enum TranscodingSettingType + { + Profile } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index 3e6832123..5b78b6789 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.LiveTv public override string GetClientTypeName() { - return "Channel"; + return "TvChannel"; } public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 2dc444ea9..87fdc66f9 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -71,6 +71,10 @@ <Compile Include="Channels\ChannelItemInfo.cs" /> <Compile Include="Channels\IChannel.cs" /> <Compile Include="Channels\IChannelManager.cs" /> + <Compile Include="Channels\IChannelItem.cs" /> + <Compile Include="Channels\ChannelAudioItem.cs" /> + <Compile Include="Channels\ChannelVideoItem.cs" /> + <Compile Include="Channels\Channel.cs" /> <Compile Include="Collections\CollectionCreationOptions.cs" /> <Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Dlna\DeviceIdentification.cs" /> diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index b0c1e1749..e8c1b9579 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -26,8 +26,6 @@ namespace MediaBrowser.Dlna { var list = new List<DeviceProfile>(); - #region Samsung - list.Add(new DeviceProfile { Name = "Samsung TV (B Series)", @@ -79,8 +77,6 @@ namespace MediaBrowser.Dlna Type = DlnaProfileType.Video } } - - }); list.Add(new DeviceProfile @@ -187,10 +183,6 @@ namespace MediaBrowser.Dlna } }); - #endregion - - #region Xbox - list.Add(new DeviceProfile { Name = "Xbox 360", @@ -272,10 +264,6 @@ namespace MediaBrowser.Dlna } }); - #endregion - - #region Sony - list.Add(new DeviceProfile { Name = "Sony Bravia (2012)", @@ -369,10 +357,6 @@ namespace MediaBrowser.Dlna } }); - #endregion - - #region Panasonic - list.Add(new DeviceProfile { //Panasonic Viera (2011|2012) Without AVI Support @@ -461,8 +445,6 @@ namespace MediaBrowser.Dlna } }); - #endregion - //WDTV does not need any transcoding of the formats we support statically list.Add(new DeviceProfile { @@ -625,37 +607,55 @@ namespace MediaBrowser.Dlna private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo) { - if (!string.IsNullOrEmpty(profileInfo.FriendlyName)) + if (!string.IsNullOrWhiteSpace(profileInfo.DeviceDescription)) + { + if (!Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription)) + return false; + } + + if (!string.IsNullOrWhiteSpace(profileInfo.FriendlyName)) { if (!Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName)) return false; } - if (!string.IsNullOrEmpty(profileInfo.ModelNumber)) + if (!string.IsNullOrWhiteSpace(profileInfo.Manufacturer)) { - if (!Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) + if (!Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) return false; } - if (!string.IsNullOrEmpty(profileInfo.ModelName)) + if (!string.IsNullOrWhiteSpace(profileInfo.ManufacturerUrl)) + { + if (!Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) + return false; + } + + if (!string.IsNullOrWhiteSpace(profileInfo.ModelDescription)) + { + if (!Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription)) + return false; + } + + if (!string.IsNullOrWhiteSpace(profileInfo.ModelName)) { if (!Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName)) return false; } - if (!string.IsNullOrEmpty(profileInfo.Manufacturer)) + if (!string.IsNullOrWhiteSpace(profileInfo.ModelNumber)) { - if (!Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) + if (!Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) return false; } - if (!string.IsNullOrEmpty(profileInfo.ManufacturerUrl)) + if (!string.IsNullOrWhiteSpace(profileInfo.ModelUrl)) { - if (!Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) + if (!Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl)) return false; } - if (!string.IsNullOrEmpty(profileInfo.SerialNumber)) + if (!string.IsNullOrWhiteSpace(profileInfo.SerialNumber)) { if (!Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber)) return false; diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index c8df3931d..4a96c580c 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -74,6 +74,9 @@ <Compile Include="..\MediaBrowser.Model\ApiClient\ServerEventArgs.cs"> <Link>ApiClient\ServerEventArgs.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Channels\ChannelQuery.cs"> + <Link>Channels\ChannelQuery.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\AutoOrganize.cs"> <Link>Configuration\AutoOrganize.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 6e8f23089..958a4a726 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -61,6 +61,9 @@ <Compile Include="..\MediaBrowser.Model\ApiClient\ServerEventArgs.cs"> <Link>ApiClient\ServerEventArgs.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Channels\ChannelQuery.cs"> + <Link>Channels\ChannelQuery.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\AutoOrganize.cs"> <Link>Configuration\AutoOrganize.cs</Link> </Compile> diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs new file mode 100644 index 000000000..13a87efb6 --- /dev/null +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -0,0 +1,57 @@ + +namespace MediaBrowser.Model.Channels +{ + public class ChannelQuery + { + /// <summary> + /// Gets or sets the user identifier. + /// </summary> + /// <value>The user identifier.</value> + public string UserId { get; set; } + + /// <summary> + /// Skips over a given number of items within the results. Use for paging. + /// </summary> + /// <value>The start index.</value> + public int? StartIndex { get; set; } + + /// <summary> + /// The maximum number of items to return + /// </summary> + /// <value>The limit.</value> + public int? Limit { get; set; } + } + + public class ChannelItemQuery + { + /// <summary> + /// Gets or sets the channel identifier. + /// </summary> + /// <value>The channel identifier.</value> + public string ChannelId { get; set; } + + /// <summary> + /// Gets or sets the category identifier. + /// </summary> + /// <value>The category identifier.</value> + public string CategoryId { get; set; } + + /// <summary> + /// Gets or sets the user identifier. + /// </summary> + /// <value>The user identifier.</value> + public string UserId { get; set; } + + /// <summary> + /// Skips over a given number of items within the results. Use for paging. + /// </summary> + /// <value>The start index.</value> + public int? StartIndex { get; set; } + + /// <summary> + /// The maximum number of items to return + /// </summary> + /// <value>The limit.</value> + public int? Limit { get; set; } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 45172da43..cce3e74cc 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -58,6 +58,7 @@ <Compile Include="ApiClient\ApiClientExtensions.cs" /> <Compile Include="ApiClient\IServerEvents.cs" /> <Compile Include="ApiClient\ServerEventArgs.cs" /> + <Compile Include="Channels\ChannelQuery.cs" /> <Compile Include="Configuration\AutoOrganize.cs" /> <Compile Include="Configuration\BaseApplicationConfiguration.cs" /> <Compile Include="Configuration\DlnaOptions.cs" /> diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs new file mode 100644 index 000000000..3b87dcdd4 --- /dev/null +++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs @@ -0,0 +1,32 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; + +namespace MediaBrowser.Providers.Channels +{ + public class ChannelMetadataService : MetadataService<Channel, ItemLookupInfo> + { + public ChannelMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) + : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) + { + } + + /// <summary> + /// Merges the specified source. + /// </summary> + /// <param name="source">The source.</param> + /// <param name="target">The target.</param> + /// <param name="lockedFields">The locked fields.</param> + /// <param name="replaceData">if set to <c>true</c> [replace data].</param> + /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param> + protected override void MergeData(Channel source, Channel target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + } +} diff --git a/MediaBrowser.Providers/GameGenres/AudioChannelItemMetadataService.cs b/MediaBrowser.Providers/GameGenres/AudioChannelItemMetadataService.cs new file mode 100644 index 000000000..c8e496b71 --- /dev/null +++ b/MediaBrowser.Providers/GameGenres/AudioChannelItemMetadataService.cs @@ -0,0 +1,32 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; + +namespace MediaBrowser.Providers.GameGenres +{ + public class AudioChannelItemMetadataService : MetadataService<ChannelAudioItem, ItemLookupInfo> + { + public AudioChannelItemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) + : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) + { + } + + /// <summary> + /// Merges the specified source. + /// </summary> + /// <param name="source">The source.</param> + /// <param name="target">The target.</param> + /// <param name="lockedFields">The locked fields.</param> + /// <param name="replaceData">if set to <c>true</c> [replace data].</param> + /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param> + protected override void MergeData(ChannelAudioItem source, ChannelAudioItem target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + } +} diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs index 0eaed59c7..f5659f2d9 100644 --- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs +++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs @@ -7,8 +7,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Providers.GameGenres { diff --git a/MediaBrowser.Providers/GameGenres/VideoChannelItemMetadataService.cs b/MediaBrowser.Providers/GameGenres/VideoChannelItemMetadataService.cs new file mode 100644 index 000000000..9dd37c959 --- /dev/null +++ b/MediaBrowser.Providers/GameGenres/VideoChannelItemMetadataService.cs @@ -0,0 +1,32 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; + +namespace MediaBrowser.Providers.GameGenres +{ + public class VideoChannelItemMetadataService : MetadataService<ChannelVideoItem, ItemLookupInfo> + { + public VideoChannelItemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem) + : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) + { + } + + /// <summary> + /// Merges the specified source. + /// </summary> + /// <param name="source">The source.</param> + /// <param name="target">The target.</param> + /// <param name="lockedFields">The locked fields.</param> + /// <param name="replaceData">if set to <c>true</c> [replace data].</param> + /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param> + protected override void MergeData(ChannelVideoItem source, ChannelVideoItem target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + } +} diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 395e66529..f347e7229 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -78,10 +78,13 @@ <Compile Include="BoxSets\BoxSetXmlParser.cs" /> <Compile Include="BoxSets\MovieDbBoxSetImageProvider.cs" /> <Compile Include="BoxSets\MovieDbBoxSetProvider.cs" /> + <Compile Include="Channels\ChannelMetadataService.cs" /> <Compile Include="Folders\CollectionFolderImageProvider.cs" /> <Compile Include="Folders\FolderMetadataService.cs" /> <Compile Include="Folders\ImagesByNameImageProvider.cs" /> + <Compile Include="GameGenres\AudioChannelItemMetadataService.cs" /> <Compile Include="GameGenres\GameGenreMetadataService.cs" /> + <Compile Include="GameGenres\VideoChannelItemMetadataService.cs" /> <Compile Include="Games\GameMetadataService.cs" /> <Compile Include="Games\GameSystemMetadataService.cs" /> <Compile Include="Games\GameSystemXmlParser.cs" /> diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs new file mode 100644 index 000000000..23504aaaa --- /dev/null +++ b/MediaBrowser.Server.Implementations/Channels/ChannelItemImageProvider.cs @@ -0,0 +1,87 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Channels +{ + public class ChannelItemImageProvider : IDynamicImageProvider, IHasChangeMonitor + { + private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + + public ChannelItemImageProvider(IHttpClient httpClient, ILogger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public IEnumerable<ImageType> GetSupportedImages(IHasImages item) + { + return new[] { ImageType.Primary }; + } + + public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken) + { + var channelItem = (IChannelItem)item; + + var imageResponse = new DynamicImageResponse(); + + if (!string.IsNullOrEmpty(channelItem.OriginalImageUrl)) + { + var options = new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = channelItem.OriginalImageUrl + }; + + var response = await _httpClient.GetResponse(options).ConfigureAwait(false); + + if (response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) + { + imageResponse.HasImage = true; + imageResponse.Stream = response.Content; + imageResponse.SetFormatFromMimeType(response.ContentType); + } + else + { + _logger.Error("Provider did not return an image content type."); + } + } + + return imageResponse; + } + + public string Name + { + get { return "Channel Image Provider"; } + } + + public bool Supports(IHasImages item) + { + return item is IChannelItem; + } + + public int Order + { + get { return 0; } + } + + public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) + { + var channelItem = item as IChannelItem; + + if (channelItem != null) + { + return !channelItem.HasImage(ImageType.Primary) && !string.IsNullOrWhiteSpace(channelItem.OriginalImageUrl); + } + return false; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs new file mode 100644 index 000000000..630c7373e --- /dev/null +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -0,0 +1,257 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Channels +{ + public class ChannelManager : IChannelManager + { + private IChannel[] _channels; + private List<Channel> _channelEntities = new List<Channel>(); + + private readonly IUserManager _userManager; + private readonly IDtoService _dtoService; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; + + public ChannelManager(IUserManager userManager, IDtoService dtoService, ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem) + { + _userManager = userManager; + _dtoService = dtoService; + _libraryManager = libraryManager; + _logger = logger; + _config = config; + _fileSystem = fileSystem; + } + + public void AddParts(IEnumerable<IChannel> channels) + { + _channels = channels.ToArray(); + } + + public Task<QueryResult<BaseItemDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken) + { + var user = string.IsNullOrWhiteSpace(query.UserId) + ? null + : _userManager.GetUserById(new Guid(query.UserId)); + + var channels = _channelEntities.OrderBy(i => i.SortName).ToList(); + + if (user != null) + { + channels = channels.Where(i => GetChannelProvider(i).IsEnabledFor(user) && i.IsVisible(user)) + .ToList(); + } + + // Get everything + var fields = Enum.GetNames(typeof(ItemFields)) + .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) + .ToList(); + + var returnItems = channels.Select(i => _dtoService.GetBaseItemDto(i, fields, user)) + .ToArray(); + + var result = new QueryResult<BaseItemDto> + { + Items = returnItems, + TotalRecordCount = returnItems.Length + }; + + return Task.FromResult(result); + } + + public async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken) + { + var allChannelsList = _channels.ToList(); + + var list = new List<Channel>(); + + var numComplete = 0; + + foreach (var channelInfo in allChannelsList) + { + cancellationToken.ThrowIfCancellationRequested(); + + try + { + var item = await GetChannel(channelInfo, cancellationToken).ConfigureAwait(false); + + list.Add(item); + + _libraryManager.RegisterItem(item); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channel information for {0}", ex, channelInfo.Name); + } + + numComplete++; + double percent = numComplete; + percent /= allChannelsList.Count; + + progress.Report(100 * percent); + } + + _channelEntities = list.ToList(); + progress.Report(100); + } + + private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken) + { + var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name)); + + var fileInfo = new DirectoryInfo(path); + + var isNew = false; + + if (!fileInfo.Exists) + { + _logger.Debug("Creating directory {0}", path); + + Directory.CreateDirectory(path); + fileInfo = new DirectoryInfo(path); + + if (!fileInfo.Exists) + { + throw new IOException("Path not created: " + path); + } + + isNew = true; + } + + var id = GetInternalChannelId(channelInfo.Name); + + var item = _libraryManager.GetItemById(id) as Channel; + + if (item == null) + { + item = new Channel + { + Name = channelInfo.Name, + Id = id, + DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo), + DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo), + Path = path + }; + + isNew = true; + } + + item.HomePageUrl = channelInfo.HomePageUrl; + item.OriginalChannelName = channelInfo.Name; + + if (string.IsNullOrEmpty(item.Name)) + { + item.Name = channelInfo.Name; + } + + await item.RefreshMetadata(new MetadataRefreshOptions + { + ForceSave = isNew + + }, cancellationToken); + + return item; + } + + private Guid GetInternalChannelId(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + + return ("Channel " + name).GetMBId(typeof(Channel)); + } + + public async Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken) + { + var user = string.IsNullOrWhiteSpace(query.UserId) + ? null + : _userManager.GetUserById(new Guid(query.UserId)); + + var id = new Guid(query.ChannelId); + var channel = _channelEntities.First(i => i.Id == id); + var channelProvider = GetChannelProvider(channel); + + var items = await GetChannelItems(channelProvider, user, query.CategoryId, cancellationToken) + .ConfigureAwait(false); + + + return await GetReturnItems(items, user, query.StartIndex, query.Limit, cancellationToken).ConfigureAwait(false); + } + + private Task<IEnumerable<ChannelItemInfo>> GetChannelItems(IChannel channel, User user, string categoryId, CancellationToken cancellationToken) + { + // TODO: Put some caching in here + + if (string.IsNullOrWhiteSpace(categoryId)) + { + return channel.GetChannelItems(user, cancellationToken); + } + + return channel.GetChannelItems(categoryId, user, cancellationToken); + } + + private async Task<QueryResult<BaseItemDto>> GetReturnItems(IEnumerable<ChannelItemInfo> items, User user, int? startIndex, int? limit, CancellationToken cancellationToken) + { + if (startIndex.HasValue) + { + items = items.Skip(startIndex.Value); + } + if (limit.HasValue) + { + items = items.Take(limit.Value); + } + + // Get everything + var fields = Enum.GetNames(typeof(ItemFields)) + .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) + .ToList(); + + var tasks = items.Select(GetChannelItemEntity); + + var returnItems = await Task.WhenAll(tasks).ConfigureAwait(false); + + var returnItemArray = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)) + .ToArray(); + + return new QueryResult<BaseItemDto> + { + Items = returnItemArray, + TotalRecordCount = returnItems.Length + }; + } + + private async Task<BaseItem> GetChannelItemEntity(ChannelItemInfo info) + { + return null; + } + + private IChannel GetChannelProvider(Channel channel) + { + return _channels.First(i => string.Equals(i.Name, channel.OriginalChannelName, StringComparison.OrdinalIgnoreCase)); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index e4446895f..6a4c3930a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -306,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private async Task<LiveTvChannel> GetChannel(ChannelInfo channelInfo, string serviceName, CancellationToken cancellationToken) { - var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name)); + var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "tvchannels", _fileSystem.GetValidFilename(channelInfo.Name)); var fileInfo = new DirectoryInfo(path); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 871565133..495288e4f 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -106,6 +106,8 @@ <Link>Properties\SharedVersion.cs</Link> </Compile> <Compile Include="BdInfo\BdInfoExaminer.cs" /> + <Compile Include="Channels\ChannelItemImageProvider.cs" /> + <Compile Include="Channels\ChannelManager.cs" /> <Compile Include="Collections\CollectionManager.cs" /> <Compile Include="Collections\CollectionsDynamicFolder.cs" /> <Compile Include="Configuration\ServerConfigurationManager.cs" /> diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 43aeb0ab0..00fd63d93 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -9,6 +9,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; @@ -39,6 +40,7 @@ using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Manager; using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Implementations.BdInfo; +using MediaBrowser.Server.Implementations.Channels; using MediaBrowser.Server.Implementations.Collections; using MediaBrowser.Server.Implementations.Configuration; using MediaBrowser.Server.Implementations.Drawing; @@ -489,6 +491,9 @@ namespace MediaBrowser.ServerApplication MediaEncoder); RegisterSingleInstance(EncodingManager); + var channelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager); + RegisterSingleInstance<IChannelManager>(channelManager); + var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance<IAppThemeManager>(appThemeManager); diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 15f160942..d34bc574a 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -156,9 +156,7 @@ <Content Include="dashboard-ui\css\images\icons\audiocd.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\icons\filter.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
+ <Content Include="dashboard-ui\css\images\icons\filter.png" />
<Content Include="dashboard-ui\css\images\icons\mute.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -174,9 +172,6 @@ <Content Include="dashboard-ui\css\images\icons\previoustrack.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\icons\remote.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\sort.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -186,9 +181,6 @@ <Content Include="dashboard-ui\css\images\icons\subtitles.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\icons\tv.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\volumedown.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
|
