mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-02 22:08:27 +01:00
update tuner setup
This commit is contained in:
@@ -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);
|
||||
})
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -484,43 +484,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
|
||||
|
||||
private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var username = info.Username;
|
||||
|
||||
// Reset the token if there's no username
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var password = info.Password;
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NameValuePair savedToken = null;
|
||||
if (!_tokens.TryGetValue(username, out savedToken))
|
||||
{
|
||||
savedToken = new NameValuePair();
|
||||
_tokens.TryAdd(username, savedToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value))
|
||||
{
|
||||
long ticks;
|
||||
if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
|
||||
{
|
||||
// If it's under 24 hours old we can still use it
|
||||
if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks)
|
||||
{
|
||||
return savedToken.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var username = info.Username;
|
||||
|
||||
// Reset the token if there's no username
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var password = info.Password;
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NameValuePair savedToken = null;
|
||||
if (!_tokens.TryGetValue(username, out savedToken))
|
||||
{
|
||||
savedToken = new NameValuePair();
|
||||
_tokens.TryAdd(username, savedToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value))
|
||||
{
|
||||
long ticks;
|
||||
if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks))
|
||||
{
|
||||
// If it's under 24 hours old we can still use it
|
||||
if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks)
|
||||
{
|
||||
return savedToken.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,5 +185,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Validate(TunerHostInfo info)
|
||||
{
|
||||
if (!File.Exists(info.Url))
|
||||
{
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user