update tuner setup

This commit is contained in:
Luke Pulverenti 2015-07-23 09:23:22 -04:00
parent f9f29de05e
commit 3fda8ec5c2
14 changed files with 262 additions and 65 deletions

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@ -345,6 +346,31 @@ namespace MediaBrowser.Api.LiveTv
public string Id { get; set; }
}
[Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")]
[Authenticated]
public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo>
{
}
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
[Authenticated]
public class DeleteListingProvider : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")]
public string Id { get; set; }
}
[Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")]
[Authenticated]
public class GetLineups : IReturn<List<NameIdPair>>
{
[ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Id { get; set; }
[ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Location { get; set; }
}
public class LiveTvService : BaseApiService
{
private readonly ILiveTvManager _liveTvManager;
@ -373,20 +399,27 @@ namespace MediaBrowser.Api.LiveTv
}
}
public void Post(AddTunerHost request)
public object Post(AddListingProvider request)
{
var result = _liveTvManager.SaveListingProvider(request).Result;
return ToOptimizedResult(result);
}
public void Delete(DeleteListingProvider request)
{
var config = GetConfiguration();
config.TunerHosts.Add(new TunerHostInfo
{
Id = Guid.NewGuid().ToString("N"),
Url = request.Url,
Type = request.Type
});
config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList();
_config.SaveConfiguration("livetv", config);
}
public void Post(AddTunerHost request)
{
var task = _liveTvManager.SaveTunerHost(request);
Task.WaitAll(task);
}
public void Delete(DeleteTunerHost request)
{
var config = GetConfiguration();
@ -401,6 +434,13 @@ namespace MediaBrowser.Api.LiveTv
return _config.GetConfiguration<LiveTvOptions>("livetv");
}
public async Task<object> Get(GetLineups request)
{
var info = await _liveTvManager.GetLineups(request.Id, request.Location).ConfigureAwait(false);
return ToOptimizedSerializedResultUsingCache(info);
}
public async Task<object> Get(GetLiveTvInfo request)
{
var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false);

View File

@ -1,4 +1,5 @@
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using System;
using System.Collections.Generic;
using System.Threading;
@ -9,7 +10,10 @@ namespace MediaBrowser.Controller.LiveTv
public interface IListingsProvider
{
string Name { get; }
string Type { get; }
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info);
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location);
}
}

View File

@ -61,7 +61,9 @@ namespace MediaBrowser.Controller.LiveTv
/// Adds the parts.
/// </summary>
/// <param name="services">The services.</param>
void AddParts(IEnumerable<ILiveTvService> services);
/// <param name="tunerHosts">The tuner hosts.</param>
/// <param name="listingProviders">The listing providers.</param>
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
/// <summary>
/// Gets the channels.
@ -337,5 +339,24 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="dto">The dto.</param>
/// <param name="user">The user.</param>
void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null);
/// <summary>
/// Saves the tuner host.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>Task.</returns>
Task SaveTunerHost(TunerHostInfo info);
/// <summary>
/// Saves the listing provider.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>Task.</returns>
Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info);
/// <summary>
/// Gets the lineups.
/// </summary>
/// <param name="providerId">The provider identifier.</param>
/// <param name="location">The location.</param>
/// <returns>Task&lt;List&lt;NameIdPair&gt;&gt;.</returns>
Task<List<NameIdPair>> GetLineups(string providerId, string location);
}
}

View File

@ -46,5 +46,11 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken);
/// <summary>
/// Validates the specified information.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>Task.</returns>
Task Validate(TunerHostInfo info);
}
}

View File

@ -28,10 +28,11 @@ namespace MediaBrowser.Model.LiveTv
public class ListingsProviderInfo
{
public string ProviderName { get; set; }
public string Id { get; set; }
public string Type { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string ZipCode { get; set; }
public string ListingsId { get; set; }
public string ZipCode { get; set; }
}
}

View File

@ -30,18 +30,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ItemDataProvider<SeriesTimerInfo> _seriesTimerProvider;
private readonly TimerManager _timerProvider;
private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>();
private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
private readonly LiveTvManager _liveTvManager;
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config)
public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager)
{
_appHpst = appHost;
_logger = logger;
_httpClient = httpClient;
_config = config;
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
_tunerHosts.AddRange(appHost.GetExports<ITunerHost>());
_listingProviders.AddRange(appHost.GetExports<IListingsProvider>());
_recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
_seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
@ -76,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var status = new LiveTvServiceStatusInfo();
var list = new List<LiveTvTunerInfo>();
foreach (var host in _tunerHosts)
foreach (var host in _liveTvManager.TunerHosts)
{
foreach (var hostInstance in host.GetTunerHosts())
{
@ -104,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var list = new List<ChannelInfo>();
foreach (var host in _tunerHosts)
foreach (var host in _liveTvManager.TunerHosts)
{
foreach (var hostInstance in host.GetTunerHosts())
{
@ -288,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return GetConfiguration().ListingProviders
.Select(i =>
{
var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase));
var provider = _liveTvManager.ListingProviders.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase));
return provider == null ? null : new Tuple<IListingsProvider, ListingsProviderInfo>(provider, i);
})

View File

@ -422,7 +422,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return images;
}
public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken)
public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string location, CancellationToken cancellationToken)
{
var token = await GetToken(info, cancellationToken);
@ -437,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
var options = new HttpRequestOptions()
{
Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode,
Url = ApiUrl + "/headends?country=USA&postalcode=" + location,
UserAgent = UserAgent,
CancellationToken = cancellationToken
};
@ -483,9 +483,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken)
{
await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
var username = info.Username;
@ -521,6 +518,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
}
await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false);
savedToken.Name = result;
savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
@ -563,6 +563,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
get { return "Schedules Direct"; }
}
public string Type
{
get { return "SchedulesDirect"; }
}
public class ScheduleDirect
{
public class Token
@ -842,5 +847,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
}
public async Task Validate(ListingsProviderInfo info)
{
}
public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location)
{
return GetHeadends(info, location, CancellationToken.None);
}
}
}

View File

@ -57,6 +57,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly ConcurrentDictionary<Guid, Guid> _refreshedPrograms = new ConcurrentDictionary<Guid, Guid>();
private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>();
private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>();
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
{
_config = config;
@ -92,9 +95,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
/// Adds the parts.
/// </summary>
/// <param name="services">The services.</param>
public void AddParts(IEnumerable<ILiveTvService> services)
/// <param name="tunerHosts">The tuner hosts.</param>
/// <param name="listingProviders">The listing providers.</param>
public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders)
{
_services.AddRange(services);
_tunerHosts.AddRange(tunerHosts);
_listingProviders.AddRange(listingProviders);
foreach (var service in _services)
{
@ -102,6 +109,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
public List<ITunerHost> TunerHosts
{
get { return _tunerHosts; }
}
public List<IListingsProvider> ListingProviders
{
get { return _listingProviders; }
}
void service_DataSourceChanged(object sender, EventArgs e)
{
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
@ -2154,5 +2171,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var user = _userManager.GetUserById(userId);
return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false);
}
public async Task SaveTunerHost(TunerHostInfo info)
{
info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo));
var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
if (provider == null)
{
throw new ResourceNotFoundException();
}
await provider.Validate(info).ConfigureAwait(false);
var config = GetConfiguration();
var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
info.Id = Guid.NewGuid().ToString("N");
config.TunerHosts.Add(info);
}
else
{
config.TunerHosts[index] = info;
}
_config.SaveConfiguration("livetv", config);
}
public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info)
{
info = (ListingsProviderInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(ListingsProviderInfo));
var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
if (provider == null)
{
throw new ResourceNotFoundException();
}
await provider.Validate(info).ConfigureAwait(false);
var config = GetConfiguration();
var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
info.Id = Guid.NewGuid().ToString("N");
config.ListingProviders.Add(info);
}
else
{
config.ListingProviders[index] = info;
}
_config.SaveConfiguration("livetv", config);
return info;
}
public Task<List<NameIdPair>> GetLineups(string providerId, string location)
{
var config = GetConfiguration();
var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase));
var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase));
if (provider == null)
{
throw new ResourceNotFoundException();
}
return provider.GetLineups(info, location);
}
}
}

View File

@ -3,7 +3,6 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
@ -15,7 +14,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
@ -222,5 +220,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
throw new ApplicationException("Channel not found.");
}
public async Task Validate(TunerHostInfo info)
{
await GetChannels(info, CancellationToken.None).ConfigureAwait(false);
}
}
}

View File

@ -185,5 +185,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
}
}
public async Task Validate(TunerHostInfo info)
{
if (!File.Exists(info.Url))
{
throw new FileNotFoundException();
}
}
}
}

View File

@ -820,5 +820,8 @@
"MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?",
"MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?",
"HeaderDeleteProvider": "Delete Provider",
"HeaderAddProvider": "Add Provider"
"HeaderAddProvider": "Add Provider",
"ErrorAddingTunerDevice": "There was an error adding the tuner device. Please ensure it is accessible and try again.",
"ErrorSavingTvProvider": "There was an error saving the TV provider. Please ensure it is accessible and try again.",
"ErrorGettingTvLineups": "There was an error downloading tv lineups. Please ensure your username and password are correct and try again."
}

View File

@ -1483,5 +1483,8 @@
"TabTuners": "Tuners",
"HeaderGuideProviders": "Guide Providers",
"AddGuideProviderHelp": "Add a source for TV Guide information",
"LabelZipCode": "Zip Code"
"LabelZipCode": "Zip Code:",
"GuideProviderListingsStep": "Step 2: Select Listings",
"GuideProviderLoginStep": "Step 1: Login",
"LabelLineup": "Lineup"
}

View File

@ -784,7 +784,7 @@ namespace MediaBrowser.Server.Startup.Common
ImageProcessor.AddParts(GetExports<IImageEnhancer>());
LiveTvManager.AddParts(GetExports<ILiveTvService>());
LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
ChapterManager.AddParts(GetExports<IChapterProvider>());

View File

@ -183,7 +183,7 @@
<Content Include="dashboard-ui\livetvguide.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\livetvguidesettings.html">
<Content Include="dashboard-ui\livetvguideprovider-scd.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\livetvrecordings.html">
@ -207,7 +207,7 @@
<Content Include="dashboard-ui\scripts\homeupcoming.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\livetvguidesettings.js">
<Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\mypreferenceshome.js">