commit
4ea4236460
|
@ -491,13 +491,17 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IConfigurationManager _config;
|
private readonly IConfigurationManager _config;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly IDtoService _dtoService;
|
||||||
|
|
||||||
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient)
|
public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService)
|
||||||
{
|
{
|
||||||
_liveTvManager = liveTvManager;
|
_liveTvManager = liveTvManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_config = config;
|
_config = config;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
_dtoService = dtoService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
public async Task<object> Get(GetLiveTvRegistrationInfo request)
|
||||||
|
@ -593,7 +597,7 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
|
|
||||||
public async Task<object> Get(GetChannels request)
|
public async Task<object> Get(GetChannels request)
|
||||||
{
|
{
|
||||||
var result = await _liveTvManager.GetChannels(new LiveTvChannelQuery
|
var channelResult = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
|
||||||
{
|
{
|
||||||
ChannelType = request.Type,
|
ChannelType = request.Type,
|
||||||
UserId = request.UserId,
|
UserId = request.UserId,
|
||||||
|
@ -605,16 +609,30 @@ namespace MediaBrowser.Api.LiveTv
|
||||||
EnableFavoriteSorting = request.EnableFavoriteSorting,
|
EnableFavoriteSorting = request.EnableFavoriteSorting,
|
||||||
AddCurrentProgram = request.AddCurrentProgram
|
AddCurrentProgram = request.AddCurrentProgram
|
||||||
|
|
||||||
}, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
|
}, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
|
var returnArray = _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ToArray();
|
||||||
|
|
||||||
|
var result = new QueryResult<BaseItemDto>
|
||||||
|
{
|
||||||
|
Items = returnArray,
|
||||||
|
TotalRecordCount = channelResult.TotalRecordCount
|
||||||
|
};
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedSerializedResultUsingCache(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<object> Get(GetChannel request)
|
public object Get(GetChannel request)
|
||||||
{
|
{
|
||||||
var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var result = await _liveTvManager.GetChannel(request.Id, CancellationToken.None, user).ConfigureAwait(false);
|
var item = _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
|
var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedSerializedResultUsingCache(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto
|
||||||
public List<ImageType> ImageTypes { get; set; }
|
public List<ImageType> ImageTypes { get; set; }
|
||||||
public int ImageTypeLimit { get; set; }
|
public int ImageTypeLimit { get; set; }
|
||||||
public bool EnableImages { get; set; }
|
public bool EnableImages { get; set; }
|
||||||
|
public bool AddProgramRecordingInfo { get; set; }
|
||||||
public string DeviceId { get; set; }
|
public string DeviceId { get; set; }
|
||||||
|
|
||||||
public DtoOptions()
|
public DtoOptions()
|
||||||
|
|
|
@ -74,15 +74,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <param name="listingProviders">The listing providers.</param>
|
/// <param name="listingProviders">The listing providers.</param>
|
||||||
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
|
void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the channels.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="query">The query.</param>
|
|
||||||
/// <param name="options">The options.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>IEnumerable{Channel}.</returns>
|
|
||||||
Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the recording.
|
/// Gets the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -93,15 +84,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <returns>Task{RecordingInfoDto}.</returns>
|
/// <returns>Task{RecordingInfoDto}.</returns>
|
||||||
Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
|
Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the channel.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The identifier.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>Task{RecordingInfoDto}.</returns>
|
|
||||||
Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the timer.
|
/// Gets the timer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -385,11 +367,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the channel information.
|
/// Adds the channel information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto">The dto.</param>
|
/// <param name="items">The items.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
|
||||||
/// <param name="options">The options.</param>
|
/// <param name="options">The options.</param>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user);
|
void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when [recording file deleted].
|
/// Called when [recording file deleted].
|
||||||
|
|
|
@ -94,12 +94,18 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
|
|
||||||
var list = new List<BaseItemDto>();
|
var list = new List<BaseItemDto>();
|
||||||
var programTuples = new List<Tuple<BaseItem, BaseItemDto>> { };
|
var programTuples = new List<Tuple<BaseItem, BaseItemDto>> { };
|
||||||
|
var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>> { };
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
var dto = GetBaseItemDtoInternal(item, options, syncDictionary, user, owner);
|
var dto = GetBaseItemDtoInternal(item, options, syncDictionary, user, owner);
|
||||||
|
|
||||||
if (item is LiveTvProgram)
|
var tvChannel = item as LiveTvChannel;
|
||||||
|
if (tvChannel != null)
|
||||||
|
{
|
||||||
|
channelTuples.Add(new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel));
|
||||||
|
}
|
||||||
|
else if (item is LiveTvProgram)
|
||||||
{
|
{
|
||||||
programTuples.Add(new Tuple<BaseItem, BaseItemDto>(item, dto));
|
programTuples.Add(new Tuple<BaseItem, BaseItemDto>(item, dto));
|
||||||
}
|
}
|
||||||
|
@ -131,6 +137,11 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
Task.WaitAll(task);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channelTuples.Count > 0)
|
||||||
|
{
|
||||||
|
_livetvManager().AddChannelInfo(channelTuples, options, user);
|
||||||
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,8 +162,13 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
var syncProgress = GetSyncedItemProgress(options);
|
var syncProgress = GetSyncedItemProgress(options);
|
||||||
|
|
||||||
var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user, owner);
|
var dto = GetBaseItemDtoInternal(item, options, GetSyncedItemProgressDictionary(syncProgress), user, owner);
|
||||||
|
var tvChannel = item as LiveTvChannel;
|
||||||
if (item is LiveTvProgram)
|
if (tvChannel != null)
|
||||||
|
{
|
||||||
|
var list = new List<Tuple<BaseItemDto, LiveTvChannel>> { new Tuple<BaseItemDto, LiveTvChannel>(dto, tvChannel) };
|
||||||
|
_livetvManager().AddChannelInfo(list, options, user);
|
||||||
|
}
|
||||||
|
else if (item is LiveTvProgram)
|
||||||
{
|
{
|
||||||
var list = new List<Tuple<BaseItem, BaseItemDto>> { new Tuple<BaseItem, BaseItemDto>(item, dto) };
|
var list = new List<Tuple<BaseItem, BaseItemDto>> { new Tuple<BaseItem, BaseItemDto>(item, dto) };
|
||||||
var task = _livetvManager().AddInfoToProgramDto(list, options.Fields, user);
|
var task = _livetvManager().AddInfoToProgramDto(list, options.Fields, user);
|
||||||
|
@ -372,12 +388,6 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
|
|
||||||
AttachBasicFields(dto, item, owner, options);
|
AttachBasicFields(dto, item, owner, options);
|
||||||
|
|
||||||
var tvChannel = item as LiveTvChannel;
|
|
||||||
if (tvChannel != null)
|
|
||||||
{
|
|
||||||
_livetvManager().AddChannelInfo(dto, tvChannel, options, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
var collectionFolder = item as ICollectionFolder;
|
var collectionFolder = item as ICollectionFolder;
|
||||||
if (collectionFolder != null)
|
if (collectionFolder != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,21 +152,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert the provider 0-5 scale to our 0-10 scale
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private float? GetClientCommunityRating(float? val)
|
|
||||||
{
|
|
||||||
if (!val.HasValue)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveTvTunerInfoDto GetTunerInfoDto(string serviceName, LiveTvTunerInfo info, string channelName)
|
public LiveTvTunerInfoDto GetTunerInfoDto(string serviceName, LiveTvTunerInfo info, string channelName)
|
||||||
{
|
{
|
||||||
var dto = new LiveTvTunerInfoDto
|
var dto = new LiveTvTunerInfoDto
|
||||||
|
@ -195,54 +180,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the channel info dto.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">The info.</param>
|
|
||||||
/// <param name="options">The options.</param>
|
|
||||||
/// <param name="currentProgram">The current program.</param>
|
|
||||||
/// <param name="user">The user.</param>
|
|
||||||
/// <returns>ChannelInfoDto.</returns>
|
|
||||||
public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, DtoOptions options, LiveTvProgram currentProgram, User user = null)
|
|
||||||
{
|
|
||||||
var dto = new ChannelInfoDto
|
|
||||||
{
|
|
||||||
Name = info.Name,
|
|
||||||
ServiceName = info.ServiceName,
|
|
||||||
ChannelType = info.ChannelType,
|
|
||||||
Number = info.Number,
|
|
||||||
Type = info.GetClientTypeName(),
|
|
||||||
Id = info.Id.ToString("N"),
|
|
||||||
MediaType = info.MediaType,
|
|
||||||
ExternalId = info.ExternalId,
|
|
||||||
MediaSources = info.GetMediaSources(true).ToList(),
|
|
||||||
ServerId = _appHost.SystemId
|
|
||||||
};
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
dto.UserData = _userDataManager.GetUserDataDto(info, user);
|
|
||||||
|
|
||||||
dto.PlayAccess = info.GetPlayAccess(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageTag = GetImageTag(info);
|
|
||||||
|
|
||||||
if (imageTag != null)
|
|
||||||
{
|
|
||||||
dto.ImageTags[ImageType.Primary] = imageTag;
|
|
||||||
|
|
||||||
_dtoService.AttachPrimaryImageAspectRatio(dto, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentProgram != null)
|
|
||||||
{
|
|
||||||
dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string GetImageTag(IHasImages info)
|
internal string GetImageTag(IHasImages info)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -324,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
|
if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
|
||||||
{
|
{
|
||||||
var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false);
|
var channel = liveTv.GetInternalChannel(dto.ChannelId);
|
||||||
|
|
||||||
if (channel != null)
|
if (channel != null)
|
||||||
{
|
{
|
||||||
|
@ -387,7 +324,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
|
if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
|
||||||
{
|
{
|
||||||
var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false);
|
var channel = liveTv.GetInternalChannel(dto.ChannelId);
|
||||||
|
|
||||||
if (channel != null)
|
if (channel != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -244,42 +244,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
|
|
||||||
|
|
||||||
var internalResult = await GetInternalChannels(query, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var returnList = new List<ChannelInfoDto>();
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var programs = query.AddCurrentProgram ? _libraryManager.QueryItems(new InternalItemsQuery
|
|
||||||
{
|
|
||||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
|
||||||
MaxStartDate = now,
|
|
||||||
MinEndDate = now,
|
|
||||||
ChannelIds = internalResult.Items.Select(i => i.Id.ToString("N")).ToArray()
|
|
||||||
|
|
||||||
}).Items.Cast<LiveTvProgram>().OrderBy(i => i.StartDate).ToList() : new List<LiveTvProgram>();
|
|
||||||
|
|
||||||
foreach (var channel in internalResult.Items)
|
|
||||||
{
|
|
||||||
var channelIdString = channel.Id.ToString("N");
|
|
||||||
var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
returnList.Add(_tvDtoService.GetChannelInfoDto(channel, options, currentProgram, user));
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new QueryResult<ChannelInfoDto>
|
|
||||||
{
|
|
||||||
Items = returnList.ToArray(),
|
|
||||||
TotalRecordCount = internalResult.TotalRecordCount
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveTvChannel GetInternalChannel(string id)
|
public LiveTvChannel GetInternalChannel(string id)
|
||||||
{
|
{
|
||||||
return GetInternalChannel(new Guid(id));
|
return GetInternalChannel(new Guid(id));
|
||||||
|
@ -1859,54 +1823,39 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null)
|
public void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user)
|
||||||
{
|
{
|
||||||
var channel = GetInternalChannel(id);
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var channelIds = tuples.Select(i => i.Item2.Id.ToString("N")).Distinct().ToArray();
|
||||||
|
|
||||||
var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
||||||
ChannelIds = new[] { id },
|
ChannelIds = channelIds,
|
||||||
MaxStartDate = now,
|
MaxStartDate = now,
|
||||||
MinEndDate = now,
|
MinEndDate = now,
|
||||||
Limit = 1,
|
Limit = channelIds.Length,
|
||||||
SortBy = new[] { "StartDate" }
|
SortBy = new[] { "StartDate" }
|
||||||
|
|
||||||
}, new string[] { }).Cast<LiveTvProgram>();
|
}, new string[] { }).ToList();
|
||||||
|
|
||||||
var currentProgram = programs.FirstOrDefault();
|
foreach (var tuple in tuples)
|
||||||
|
|
||||||
var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user);
|
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user)
|
|
||||||
{
|
{
|
||||||
|
var dto = tuple.Item1;
|
||||||
|
var channel = tuple.Item2;
|
||||||
|
|
||||||
dto.MediaSources = channel.GetMediaSources(true).ToList();
|
dto.MediaSources = channel.GetMediaSources(true).ToList();
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var channelIdString = channel.Id.ToString("N");
|
||||||
|
var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
|
||||||
var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
|
|
||||||
{
|
|
||||||
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
|
|
||||||
ChannelIds = new[] { channel.Id.ToString("N") },
|
|
||||||
MaxStartDate = now,
|
|
||||||
MinEndDate = now,
|
|
||||||
Limit = 1,
|
|
||||||
SortBy = new[] { "StartDate" }
|
|
||||||
|
|
||||||
}, new string[] { }).Cast<LiveTvProgram>();
|
|
||||||
|
|
||||||
var currentProgram = programs.FirstOrDefault();
|
|
||||||
|
|
||||||
if (currentProgram != null)
|
if (currentProgram != null)
|
||||||
{
|
{
|
||||||
dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
|
dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
|
private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user