Update for Jellyfin 10.8

- Change branding from Vu+ to Enigma2

- Fix wrong default hostname

- Add new options UseLoginForStreams, UseHTTPSForStreams

- Use new GUID to avoid clashing with the older version of plugin
This commit is contained in:
knackebrot
2022-06-29 02:40:53 +02:00
parent 4a41cf4b74
commit a2e9686898
10 changed files with 226 additions and 197 deletions
@@ -0,0 +1,50 @@
using MediaBrowser.Model.Plugins;
namespace Jellyfin.Plugin.Enigma2.Configuration
{
/// <summary>
/// Class PluginConfiguration
/// </summary>
public class PluginConfiguration : BasePluginConfiguration
{
public string HostName { get; set; }
public string StreamingPort { get; set; }
public string WebInterfacePort { get; set; }
public string WebInterfaceUsername { get; set; }
public string WebInterfacePassword { get; set; }
public bool UseLoginForStreams { get; set; }
public bool UseSecureHTTPS { get; set; }
public bool UseSecureHTTPSForStreams { get; set; }
public bool OnlyOneBouquet { get; set; }
public string TVBouquet { get; set; }
public bool ZapToChannel { get; set; }
public bool FetchPiconsFromWebInterface { get; set; }
public string PiconsPath { get; set; }
public string RecordingPath { get; set; }
public bool EnableDebugLogging { get; set; }
public PluginConfiguration()
{
HostName = "localhost";
StreamingPort = "8001";
WebInterfacePort = "8000";
WebInterfaceUsername = "";
WebInterfacePassword = "";
UseLoginForStreams = false;
UseSecureHTTPS = false;
UseSecureHTTPSForStreams = false;
OnlyOneBouquet = true;
TVBouquet = "Favourites (TV)";
ZapToChannel = false;
FetchPiconsFromWebInterface = true;
PiconsPath = "";
RecordingPath = "";
EnableDebugLogging = false;
}
}
}
@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html>
<head>
<title>Enigma2</title>
</head>
<body>
<div data-role="page" id="Enigma2ConfigurationPage" class="page type-interior pluginConfigurationPage Enigma2ConfigurationPage" data-require="emby-button,emby-checkbox,emby-input">
<div data-role="content">
<div class="content-primary">
<h1>Enigma2</h1>
<form id="Enigma2ConfigurationForm" class="Enigma2ConfigurationForm">
<div class="inputContainer">
<input is="emby-input" id="txtHostName" type="text" label="Enigma2 hostname or ip address:" />
<div class="fieldDescription">
The host name (address) or ip address of your receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtStreamingPort" type="text" label="Enigma2 streaming port:" />
<div class="fieldDescription">
The Streaming port of your receiver eg. 8001
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePort" type="text" label="Enigma2 Web Interface port:" />
<div class="fieldDescription">
The web interface port of your receiver eg. 8000
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfaceUsername" type="text" label="Enigma2 Web Interface username:" />
<div class="fieldDescription">
The web interface username of your receiver (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtWebInterfacePassword" type="password" label="Enigma2 Web Interface password:" />
<div class="fieldDescription">
The web interface password of your receiver (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseLoginForStreams" />
<span>Use login for streaming</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use web interface login for streaming
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseSecureHTTPS" />
<span>Use secure HTTP (HTTPS)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use HTTPS to connect to your receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkUseSecureHTTPSForStreams" />
<span>Use secure HTTP (HTTPS) for streams</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Use HTTPS to connect to streaming port
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkOnlyOneBouquet" />
<span>Fetch Only one TV bouquet</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Limit channels to only those contained within the specified TV Bouquet below (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtTVBouquet" type="text" label="Enigma2 TVBouquet:" />
<div class="fieldDescription">
The TV Bouquet to load channels for (optional)
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkZapToChannel" />
<span>Zap before Channel switch (single tuner)</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if only one tuner within receiver
</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input is="emby-checkbox" type="checkbox" id="chkFetchPiconsFromWebInterface" />
<span>Fetch picons from webinterface</span>
</label>
<div class="fieldDescription checkboxFieldDescription">
Set if you want to retrieve Picons from the web interface of the receiver
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtPiconsPath" type="text" label="Picons Path:" />
<div class="fieldDescription">
The local location of your Picons eg. C:\Picons\ (optional)
</div>
</div>
<div class="inputContainer">
<input is="emby-input" id="txtRecordingPath" type="text" label="Recording Path:" />
<div class="fieldDescription">
The location to store your recordings on your receiver eg. /hdd/movie/ (optional)
</div>
</div>
<label class="checkboxContainer">
<input is="emby-checkbox" type="checkbox" id="chkDebugLogging" />
<span>Enable Enigma2 debug logging</span>
</label>
<div>
<button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
</div>
</form>
</div>
</div>
<script type="text/javascript">
var Enigma2ConfigurationPage = {
pluginUniqueId: "193f29f9-ea6c-4595-a6f6-55e79d7c590a",
loadConfiguration: function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId).then(function (config) {
document.getElementById('txtHostName').value = config.HostName || "";
document.getElementById('txtStreamingPort').value = config.StreamingPort || "";
document.getElementById('txtWebInterfacePort').value = config.WebInterfacePort || "";
document.getElementById('txtWebInterfaceUsername').value = config.WebInterfaceUsername || "";
document.getElementById('txtWebInterfacePassword').value = config.WebInterfacePassword || "";
document.getElementById('chkUseLoginForStreams').checked = config.UseLoginForStreams || false;
document.getElementById('chkUseSecureHTTPS').checked = config.UseSecureHTTPS || false;
document.getElementById('chkUseSecureHTTPSForStreams').checked = config.UseSecureHTTPSForStreams || false;
document.getElementById('chkOnlyOneBouquet').checked = config.OnlyOneBouquet || false;
document.getElementById('txtTVBouquet').value = config.TVBouquet || "";
document.getElementById('chkZapToChannel').checked = config.ZapToChannel || false;
document.getElementById('chkFetchPiconsFromWebInterface').checked = config.FetchPiconsFromWebInterface || false;
document.getElementById('txtPiconsPath').value = config.PiconsPath || "";
document.getElementById('txtRecordingPath').value = config.RecordingPath || "";
document.getElementById('chkDebugLogging').checked = config.EnableDebugLogging || false;
Dashboard.hideLoadingMsg();
});
},
saveConfiguration: function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId).then(function (config) {
config.HostName = document.getElementById('txtHostName').value;
config.StreamingPort = document.getElementById('txtStreamingPort').value;
config.WebInterfacePort = document.getElementById('txtWebInterfacePort').value;
config.WebInterfaceUsername = document.getElementById('txtWebInterfaceUsername').value;
config.WebInterfacePassword = document.getElementById('txtWebInterfacePassword').value;
config.UseLoginForStreams = document.getElementById('chkUseLoginForStreams').checked;
config.UseSecureHTTPS = document.getElementById('chkUseSecureHTTPS').checked;
config.UseSecureHTTPSForStreams = document.getElementById('chkUseSecureHTTPSForStreams').checked;
config.OnlyOneBouquet = document.getElementById('chkOnlyOneBouquet').checked;
config.TVBouquet = document.getElementById('txtTVBouquet').value;
config.ZapToChannel = document.getElementById('chkZapToChannel').checked;
config.FetchPiconsFromWebInterface = document.getElementById('chkFetchPiconsFromWebInterface').checked;
config.PiconsPath = document.getElementById('txtPiconsPath').value;
config.RecordingPath = document.getElementById('txtRecordingPath').value;
config.EnableDebugLogging = document.getElementById('chkDebugLogging').checked;
ApiClient.updatePluginConfiguration(Enigma2ConfigurationPage.pluginUniqueId, config).then(Dashboard.processPluginConfigurationUpdateResult);
});
}
}
document.getElementById('Enigma2ConfigurationPage').addEventListener('pageshow', function () {
Enigma2ConfigurationPage.loadConfiguration();
});
document.getElementById('Enigma2ConfigurationForm').addEventListener('submit', function (e) {
e.preventDefault();
Enigma2ConfigurationPage.saveConfiguration();
});
</script>
</div>
</body>
</html>
@@ -0,0 +1,71 @@
using System;
using MediaBrowser.Model.LiveTv;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Plugin.Enigma2.Helpers
{
public static class ChannelHelper
{
public static ChannelType GetChannelType(string channelType)
{
var type = new ChannelType();
if (channelType == "0x1")
{
type = ChannelType.TV;
}
else if (channelType == "0xa")
{
type = ChannelType.Radio;
}
return type;
}
}
public static class UtilsHelper
{
public static void DebugInformation(ILogger<LiveTvService> logger, string message)
{
var config = Plugin.Instance.Configuration;
var enableDebugLogging = config.EnableDebugLogging;
if (enableDebugLogging)
{
logger.LogDebug(message);
}
}
}
public static class RecordingHelper
{
}
public static class ApiHelper
{
private static readonly DateTime UnixEpoch =
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long GetCurrentUnixTimestampMillis()
{
return (long)(DateTime.UtcNow - UnixEpoch).TotalMilliseconds;
}
public static DateTime DateTimeFromUnixTimestampMillis(long millis)
{
return UnixEpoch.AddMilliseconds(millis);
}
public static long GetCurrentUnixTimestampSeconds(DateTime date)
{
return (long)(date - UnixEpoch).TotalSeconds;
}
public static DateTime DateTimeFromUnixTimestampSeconds(long seconds)
{
return UnixEpoch.AddSeconds(seconds);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<FileVersion>5.0.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<None Remove="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Configuration\configPage.html" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Jellyfin.Common" Version="10.8.0" />
<PackageReference Include="Jellyfin.Naming" Version="10.8.0" />
<PackageReference Include="Jellyfin.Controller" Version="10.8.0" />
<PackageReference Include="Jellyfin.Model" Version="10.8.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
</ItemGroup>
</Project>
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization;
using Jellyfin.Plugin.Enigma2.Configuration;
namespace Jellyfin.Plugin.Enigma2
{
/// <summary>
/// Class Plugin
/// </summary>
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
{
public Plugin(
IApplicationPaths applicationPaths,
IXmlSerializer xmlSerializer
) : base(applicationPaths, xmlSerializer)
{
Instance = this;
}
/// <summary>
/// Gets the name of the plugin
/// </summary>
/// <value>The name.</value>
public override string Name => "Enigma2";
/// <summary>
/// Gets the description.
/// </summary>
/// <value>The description.</value>
public override string Description => "Provides live TV using Enigma2 PVR as a back-end.";
private Guid _id = new Guid("193f29f9-ea6c-4595-a6f6-55e79d7c590a");
public override Guid Id => _id;
/// <summary>
/// Gets the instance.
/// </summary>
/// <value>The instance.</value>
public static Plugin Instance { get; private set; }
public IEnumerable<PluginPageInfo> GetPages()
{
return new[]
{
new PluginPageInfo
{
Name = "enigma2",
EmbeddedResourcePath = "Jellyfin.Plugin.Enigma2.Configuration.configPage.html"
}
};
}
}
}
@@ -0,0 +1,523 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
namespace Jellyfin.Plugin.Enigma2
{
public class RecordingsChannel : IChannel, IHasCacheKey, ISupportsDelete, ISupportsLatestMedia, ISupportsMediaProbe, IHasFolderAttributes
{
public ILiveTvManager _liveTvManager;
public RecordingsChannel(ILiveTvManager liveTvManager)
{
_liveTvManager = liveTvManager;
}
public string Name => "Enigma2 Recordings";
public string[] Attributes => new[] { "Recordings" };
public string Description => "Enigma2 Recordings";
public string DataVersion => "1";
public string HomePageUrl => null;
public ChannelParentalRating ParentalRating => ChannelParentalRating.GeneralAudience;
public string GetCacheKey(string userId)
{
var now = DateTime.UtcNow;
var values = new List<string>
{
now.DayOfYear.ToString(CultureInfo.InvariantCulture),
now.Hour.ToString(CultureInfo.InvariantCulture)
};
double minute = now.Minute;
minute /= 5;
values.Add(Math.Floor(minute).ToString(CultureInfo.InvariantCulture));
values.Add(GetService().LastRecordingChange.Ticks.ToString(CultureInfo.InvariantCulture));
return string.Join("-", values.ToArray());
}
public InternalChannelFeatures GetChannelFeatures()
{
return new InternalChannelFeatures
{
ContentTypes = new List<ChannelMediaContentType>
{
ChannelMediaContentType.Movie,
ChannelMediaContentType.Episode,
ChannelMediaContentType.Clip
},
MediaTypes = new List<ChannelMediaType>
{
ChannelMediaType.Audio,
ChannelMediaType.Video
},
SupportsContentDownloading = true
};
}
public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken)
{
if (type == ImageType.Primary)
{
return Task.FromResult(new DynamicImageResponse
{
Path = "https://github.com/CompoUK/MediaBrowser.Plugins.VuPlus/blob/master/src/Images/Vu+.png?raw=true",
Protocol = MediaProtocol.Http,
HasImage = true
});
}
return Task.FromResult(new DynamicImageResponse
{
HasImage = false
});
}
public IEnumerable<ImageType> GetSupportedChannelImages()
{
return new List<ImageType>
{
ImageType.Primary
};
}
public bool IsEnabledFor(string userId)
{
return true;
}
private LiveTvService GetService()
{
return _liveTvManager.Services.OfType<LiveTvService>().First();
}
public bool CanDelete(BaseItem item)
{
return !item.IsFolder;
}
public Task DeleteItem(string id, CancellationToken cancellationToken)
{
return GetService().DeleteRecordingAsync(id, cancellationToken);
}
public async Task<IEnumerable<ChannelItemInfo>> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken)
{
var result = await GetChannelItems(new InternalChannelItemQuery(), i => true, cancellationToken).ConfigureAwait(false);
return result.Items.OrderByDescending(i => i.DateCreated ?? DateTime.MinValue);
}
public Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(query.FolderId))
{
return GetRecordingGroups(query, cancellationToken);
}
if (query.FolderId.StartsWith("series_", StringComparison.OrdinalIgnoreCase))
{
var hash = query.FolderId.Split('_')[1];
return GetChannelItems(query, i => i.IsSeries && string.Equals(i.Name.GetMD5().ToString("N"), hash, StringComparison.Ordinal), cancellationToken);
}
if (string.Equals(query.FolderId, "kids", StringComparison.OrdinalIgnoreCase))
{
return GetChannelItems(query, i => i.IsKids, cancellationToken);
}
if (string.Equals(query.FolderId, "movies", StringComparison.OrdinalIgnoreCase))
{
return GetChannelItems(query, i => i.IsMovie, cancellationToken);
}
if (string.Equals(query.FolderId, "news", StringComparison.OrdinalIgnoreCase))
{
return GetChannelItems(query, i => i.IsNews, cancellationToken);
}
if (string.Equals(query.FolderId, "sports", StringComparison.OrdinalIgnoreCase))
{
return GetChannelItems(query, i => i.IsSports, cancellationToken);
}
if (string.Equals(query.FolderId, "others", StringComparison.OrdinalIgnoreCase))
{
return GetChannelItems(query, i => !i.IsSports && !i.IsNews && !i.IsMovie && !i.IsKids && !i.IsSeries, cancellationToken);
}
var result = new ChannelItemResult()
{
Items = new List<ChannelItemInfo>()
};
return Task.FromResult(result);
}
public async Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, Func<MyRecordingInfo, bool> filter, CancellationToken cancellationToken)
{
var service = GetService();
var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false);
return new ChannelItemResult()
{
Items = allRecordings.Where(filter).Select(ConvertToChannelItem).ToList()
};
}
private ChannelItemInfo ConvertToChannelItem(MyRecordingInfo item)
{
var path = string.IsNullOrEmpty(item.Path) ? item.Url : item.Path;
var channelItem = new ChannelItemInfo
{
Name = string.IsNullOrEmpty(item.EpisodeTitle) ? item.Name : item.EpisodeTitle,
SeriesName = !string.IsNullOrEmpty(item.EpisodeTitle) || item.IsSeries ? item.Name : null,
OfficialRating = item.OfficialRating,
CommunityRating = item.CommunityRating,
ContentType = item.IsMovie ? ChannelMediaContentType.Movie : (item.IsSeries ? ChannelMediaContentType.Episode : ChannelMediaContentType.Clip),
Genres = item.Genres,
ImageUrl = item.ImageUrl,
//HomePageUrl = item.HomePageUrl
Id = item.Id,
//IndexNumber = item.IndexNumber,
MediaType = item.ChannelType == ChannelType.TV ? ChannelMediaType.Video : ChannelMediaType.Audio,
MediaSources = new List<MediaSourceInfo>
{
new MediaSourceInfo
{
Path = path,
Protocol = path.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? MediaProtocol.Http : MediaProtocol.File,
Id = item.Id
}
},
//ParentIndexNumber = item.ParentIndexNumber,
PremiereDate = item.OriginalAirDate,
//ProductionYear = item.ProductionYear,
//Studios = item.Studios,
Type = ChannelItemType.Media,
DateModified = item.DateLastUpdated,
Overview = item.Overview,
//People = item.People
IsLiveStream = item.Status == RecordingStatus.InProgress,
Etag = item.Status.ToString()
};
return channelItem;
}
private async Task<ChannelItemResult> GetRecordingGroups(InternalChannelItemQuery query, CancellationToken cancellationToken)
{
var service = GetService();
var allRecordings = await service.GetAllRecordingsAsync(cancellationToken).ConfigureAwait(false);
var series = allRecordings
.Where(i => i.IsSeries)
.ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase);
var items = new List<ChannelItemInfo>();
items.AddRange(series.OrderBy(i => i.Key).Select(i => new ChannelItemInfo
{
Name = i.Key,
FolderType = ChannelFolderType.Container,
Id = "series_" + i.Key.GetMD5().ToString("N"),
Type = ChannelItemType.Folder,
ImageUrl = i.First().ImageUrl
}));
var kids = allRecordings.FirstOrDefault(i => i.IsKids);
if (kids != null)
{
items.Add(new ChannelItemInfo
{
Name = "Kids",
FolderType = ChannelFolderType.Container,
Id = "kids",
Type = ChannelItemType.Folder,
ImageUrl = kids.ImageUrl
});
}
var movies = allRecordings.FirstOrDefault(i => i.IsMovie);
if (movies != null)
{
items.Add(new ChannelItemInfo
{
Name = "Movies",
FolderType = ChannelFolderType.Container,
Id = "movies",
Type = ChannelItemType.Folder,
ImageUrl = movies.ImageUrl
});
}
var news = allRecordings.FirstOrDefault(i => i.IsNews);
if (news != null)
{
items.Add(new ChannelItemInfo
{
Name = "News",
FolderType = ChannelFolderType.Container,
Id = "news",
Type = ChannelItemType.Folder,
ImageUrl = news.ImageUrl
});
}
var sports = allRecordings.FirstOrDefault(i => i.IsSports);
if (sports != null)
{
items.Add(new ChannelItemInfo
{
Name = "Sports",
FolderType = ChannelFolderType.Container,
Id = "sports",
Type = ChannelItemType.Folder,
ImageUrl = sports.ImageUrl
});
}
var other = allRecordings.FirstOrDefault(i => !i.IsSports && !i.IsNews && !i.IsMovie && !i.IsKids && !i.IsSeries);
if (other != null)
{
items.Add(new ChannelItemInfo
{
Name = "Others",
FolderType = ChannelFolderType.Container,
Id = "others",
Type = ChannelItemType.Folder,
ImageUrl = other.ImageUrl
});
}
return new ChannelItemResult()
{
Items = items
};
}
}
public class MyRecordingInfo
{
/// <summary>
/// Id of the recording.
/// </summary>
public string Id { get; set; }
/// <summary>
/// Gets or sets the series timer identifier.
/// </summary>
/// <value>The series timer identifier.</value>
public string SeriesTimerId { get; set; }
/// <summary>
/// Gets or sets the timer identifier.
/// </summary>
/// <value>The timer identifier.</value>
public string TimerId { get; set; }
/// <summary>
/// ChannelId of the recording.
/// </summary>
public string ChannelId { get; set; }
/// <summary>
/// Gets or sets the type of the channel.
/// </summary>
/// <value>The type of the channel.</value>
public ChannelType ChannelType { get; set; }
/// <summary>
/// Name of the recording.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
public string Path { get; set; }
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>The URL.</value>
public string Url { get; set; }
/// <summary>
/// Gets or sets the overview.
/// </summary>
/// <value>The overview.</value>
public string Overview { get; set; }
/// <summary>
/// The start date of the recording, in UTC.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// The end date of the recording, in UTC.
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// Gets or sets the program identifier.
/// </summary>
/// <value>The program identifier.</value>
public string ProgramId { get; set; }
/// <summary>
/// Gets or sets the status.
/// </summary>
/// <value>The status.</value>
public RecordingStatus Status { get; set; }
/// <summary>
/// Genre of the program.
/// </summary>
public List<string> Genres { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is repeat.
/// </summary>
/// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
public bool IsRepeat { get; set; }
/// <summary>
/// Gets or sets the episode title.
/// </summary>
/// <value>The episode title.</value>
public string EpisodeTitle { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is hd.
/// </summary>
/// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
public bool? IsHD { get; set; }
/// <summary>
/// Gets or sets the audio.
/// </summary>
/// <value>The audio.</value>
public ProgramAudio? Audio { get; set; }
/// <summary>
/// Gets or sets the original air date.
/// </summary>
/// <value>The original air date.</value>
public DateTime? OriginalAirDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is movie.
/// </summary>
/// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
public bool IsMovie { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is sports.
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
public bool IsSports { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
/// </summary>
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
public bool IsSeries { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is live.
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
public bool IsLive { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
public bool IsNews { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
public bool IsKids { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is premiere.
/// </summary>
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
public bool IsPremiere { get; set; }
/// <summary>
/// Gets or sets the official rating.
/// </summary>
/// <value>The official rating.</value>
public string OfficialRating { get; set; }
/// <summary>
/// Gets or sets the community rating.
/// </summary>
/// <value>The community rating.</value>
public float? CommunityRating { get; set; }
/// <summary>
/// Supply the image path if it can be accessed directly from the file system
/// </summary>
/// <value>The image path.</value>
public string ImagePath { get; set; }
/// <summary>
/// Supply the image url if it can be downloaded
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has image.
/// </summary>
/// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
public bool? HasImage { get; set; }
/// <summary>
/// Gets or sets the show identifier.
/// </summary>
/// <value>The show identifier.</value>
public string ShowId { get; set; }
/// <summary>
/// Gets or sets the date last updated.
/// </summary>
/// <value>The date last updated.</value>
public DateTime DateLastUpdated { get; set; }
public MyRecordingInfo()
{
Genres = new List<string>();
}
}
}