mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-21 17:44:43 +01:00
updated live tv + nuget
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
{
|
||||
public class ChannelImageProvider : BaseMetadataProvider
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
public ChannelImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILiveTvManager liveTvManager, IProviderManager providerManager)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
_providerManager = providerManager;
|
||||
}
|
||||
|
||||
public override bool Supports(BaseItem item)
|
||||
{
|
||||
return item is Channel;
|
||||
}
|
||||
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
{
|
||||
if (item.HasImage(ImageType.Primary))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.NeedsRefreshInternal(item, providerInfo);
|
||||
}
|
||||
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
|
||||
{
|
||||
if (item.HasImage(ImageType.Primary))
|
||||
{
|
||||
SetLastRefreshed(item, DateTime.UtcNow);
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await DownloadImage(item, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
// Don't fail the provider on a 404
|
||||
if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task DownloadImage(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var channel = (Channel)item;
|
||||
|
||||
var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, channel.ServiceName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (service != null)
|
||||
{
|
||||
var response = await service.GetChannelImageAsync(channel.ChannelId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Dummy up the original url
|
||||
var url = channel.ServiceName + channel.ChannelId;
|
||||
|
||||
await _providerManager.SaveImage(channel, response.Content, response.ContentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override MetadataProviderPriority Priority
|
||||
{
|
||||
get { return MetadataProviderPriority.Second; }
|
||||
}
|
||||
|
||||
public override ItemUpdateType ItemUpdateType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,18 @@
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
{
|
||||
@@ -9,7 +21,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
/// </summary>
|
||||
public class LiveTvManager : ILiveTvManager
|
||||
{
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
private List<Channel> _channels = new List<Channel>();
|
||||
|
||||
private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
|
||||
|
||||
public LiveTvManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_fileSystem = fileSystem;
|
||||
_logger = logger;
|
||||
_itemRepo = itemRepo;
|
||||
_imageProcessor = imageProcessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the services.
|
||||
/// </summary>
|
||||
@@ -33,16 +63,147 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
/// </summary>
|
||||
/// <param name="info">The info.</param>
|
||||
/// <returns>ChannelInfoDto.</returns>
|
||||
public ChannelInfoDto GetChannelInfoDto(ChannelInfo info)
|
||||
public ChannelInfoDto GetChannelInfoDto(Channel info)
|
||||
{
|
||||
return new ChannelInfoDto
|
||||
{
|
||||
Name = info.Name,
|
||||
ServiceName = info.ServiceName,
|
||||
ChannelType = info.ChannelType,
|
||||
Id = info.Id,
|
||||
Number = info.Number
|
||||
Id = info.ChannelId,
|
||||
Number = info.ChannelNumber,
|
||||
PrimaryImageTag = GetLogoImageTag(info)
|
||||
};
|
||||
}
|
||||
|
||||
private Guid? GetLogoImageTag(Channel info)
|
||||
{
|
||||
var path = info.PrimaryImagePath;
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return _imageProcessor.GetImageCacheTag(info, ImageType.Primary, path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting channel image info for {0}", ex, info.Name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<Channel> GetChannels(ChannelQuery query)
|
||||
{
|
||||
return _channels.OrderBy(i =>
|
||||
{
|
||||
double number = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(i.ChannelNumber))
|
||||
{
|
||||
double.TryParse(i.ChannelNumber, out number);
|
||||
}
|
||||
|
||||
return number;
|
||||
|
||||
}).ThenBy(i => i.Name);
|
||||
}
|
||||
|
||||
public Channel GetChannel(string serviceName, string channelId)
|
||||
{
|
||||
return _channels.FirstOrDefault(i => string.Equals(i.ServiceName, serviceName, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
// Avoid implicitly captured closure
|
||||
var currentCancellationToken = cancellationToken;
|
||||
|
||||
var tasks = _services.Select(i => i.GetChannelsAsync(currentCancellationToken));
|
||||
|
||||
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
var allChannels = results.SelectMany(i => i);
|
||||
|
||||
var channnelTasks = allChannels.Select(i => GetChannel(i, cancellationToken));
|
||||
|
||||
var channelEntities = await Task.WhenAll(channnelTasks).ConfigureAwait(false);
|
||||
|
||||
_channels = channelEntities.ToList();
|
||||
}
|
||||
|
||||
private async Task<Channel> GetChannel(ChannelInfo channelInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await GetChannelInternal(channelInfo, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting channel information for {0}", ex, channelInfo.Name);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Channel> GetChannelInternal(ChannelInfo channelInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var path = Path.Combine(_appPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.ServiceName), _fileSystem.GetValidFilename(channelInfo.Name));
|
||||
|
||||
var fileInfo = new DirectoryInfo(path);
|
||||
|
||||
var isNew = false;
|
||||
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
fileInfo = new DirectoryInfo(path);
|
||||
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new IOException("Path not created: " + path);
|
||||
}
|
||||
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
var type = typeof(Channel);
|
||||
|
||||
var id = (path + channelInfo.Number).GetMBId(type);
|
||||
|
||||
var item = _itemRepo.RetrieveItem(id) as Channel;
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
item = new Channel
|
||||
{
|
||||
Name = channelInfo.Name,
|
||||
Id = id,
|
||||
DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
|
||||
Path = path,
|
||||
ChannelId = channelInfo.Id,
|
||||
ChannelNumber = channelInfo.Number,
|
||||
ServiceName = channelInfo.ServiceName
|
||||
};
|
||||
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
// Set this now so we don't cause additional file system access during provider executions
|
||||
item.ResetResolveArgs(fileInfo);
|
||||
|
||||
await item.RefreshMetadata(cancellationToken, forceSave: isNew, resetResolveArgs: false);
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using MediaBrowser.Common.ScheduledTasks;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||
{
|
||||
class RefreshChannelsScheduledTask : IScheduledTask
|
||||
{
|
||||
private readonly ILiveTvManager _liveTvManager;
|
||||
|
||||
public RefreshChannelsScheduledTask(ILiveTvManager liveTvManager)
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Refresh Channels"; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return "Downloads channel information from live tv services."; }
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get { return "Live TV"; }
|
||||
}
|
||||
|
||||
public Task Execute(System.Threading.CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var manager = (LiveTvManager) _liveTvManager;
|
||||
|
||||
return manager.RefreshChannels(progress, cancellationToken);
|
||||
}
|
||||
|
||||
public IEnumerable<ITaskTrigger> GetDefaultTriggers()
|
||||
{
|
||||
return new ITaskTrigger[]
|
||||
{
|
||||
|
||||
new StartupTrigger(),
|
||||
|
||||
new SystemEventTrigger{ SystemEvent = SystemEvent.WakeFromSleep},
|
||||
|
||||
new IntervalTrigger{ Interval = TimeSpan.FromHours(4)}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
CA-G,1
|
||||
GB-U,1
|
||||
CA-PG,5
|
||||
DE-0,5
|
||||
CA-14A,7
|
||||
DE-12,7
|
||||
CA-A,8
|
||||
CA-18A,9
|
||||
SE-11,9
|
||||
DE-16,9
|
||||
CA-R,10
|
||||
@@ -167,7 +167,9 @@
|
||||
<Compile Include="Library\Validators\StudiosPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\StudiosValidator.cs" />
|
||||
<Compile Include="Library\Validators\YearsPostScanTask.cs" />
|
||||
<Compile Include="LiveTv\ChannelImageProvider.cs" />
|
||||
<Compile Include="LiveTv\LiveTvManager.cs" />
|
||||
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
|
||||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="MediaEncoder\MediaEncoder.cs" />
|
||||
<Compile Include="Persistence\SqliteChapterRepository.cs" />
|
||||
|
||||
Reference in New Issue
Block a user