Merge pull request #3405 from crobibero/api-livetv
Move LiveTvService.cs to Jellyfin.Api
This commit is contained in:
commit
c675a9bec9
1226
Jellyfin.Api/Controllers/LiveTvController.cs
Normal file
1226
Jellyfin.Api/Controllers/LiveTvController.cs
Normal file
File diff suppressed because it is too large
Load Diff
84
Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
Normal file
84
Jellyfin.Api/Helpers/ProgressiveFileCopier.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Jellyfin.Api.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Progressive file copier.
|
||||
/// </summary>
|
||||
public class ProgressiveFileCopier
|
||||
{
|
||||
private readonly string? _path;
|
||||
private readonly IDirectStreamProvider? _directStreamProvider;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="path">Filepath to stream from.</param>
|
||||
public ProgressiveFileCopier(IStreamHelper streamHelper, string path)
|
||||
{
|
||||
_path = path;
|
||||
_streamHelper = streamHelper;
|
||||
_directStreamProvider = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="directStreamProvider">Instance of the <see cref="IDirectStreamProvider"/> interface.</param>
|
||||
public ProgressiveFileCopier(IStreamHelper streamHelper, IDirectStreamProvider directStreamProvider)
|
||||
{
|
||||
_directStreamProvider = directStreamProvider;
|
||||
_streamHelper = streamHelper;
|
||||
_path = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write source stream to output.
|
||||
/// </summary>
|
||||
/// <param name="outputStream">Output stream.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A <see cref="Task"/>.</returns>
|
||||
public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_directStreamProvider != null)
|
||||
{
|
||||
await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var fileOptions = FileOptions.SequentialScan;
|
||||
|
||||
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
|
||||
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
|
||||
{
|
||||
fileOptions |= FileOptions.Asynchronous;
|
||||
}
|
||||
|
||||
await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions);
|
||||
const int emptyReadLimit = 100;
|
||||
var eofCount = 0;
|
||||
while (eofCount < emptyReadLimit)
|
||||
{
|
||||
var bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
eofCount++;
|
||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
eofCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -144,5 +144,31 @@ namespace Jellyfin.Api.Helpers
|
|||
: Split(filters, ',', true)
|
||||
.Select(v => Enum.Parse<ItemFilter>(v, true)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item fields.
|
||||
/// </summary>
|
||||
/// <param name="fields">The fields string.</param>
|
||||
/// <returns>IEnumerable{ItemFields}.</returns>
|
||||
internal static ItemFields[] GetItemFields(string? fields)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fields))
|
||||
{
|
||||
return Array.Empty<ItemFields>();
|
||||
}
|
||||
|
||||
return Split(fields, ',', true)
|
||||
.Select(v =>
|
||||
{
|
||||
if (Enum.TryParse(v, true, out ItemFields value))
|
||||
{
|
||||
return (ItemFields?)value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}).Where(i => i.HasValue)
|
||||
.Select(i => i!.Value)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
36
Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs
Normal file
36
Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace Jellyfin.Api.Models.LiveTvDtos
|
||||
{
|
||||
/// <summary>
|
||||
/// Channel mapping options dto.
|
||||
/// </summary>
|
||||
public class ChannelMappingOptionsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets list of tuner channels.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "TunerChannels", Justification = "Imported from ServiceStack")]
|
||||
public List<TunerChannelMapping> TunerChannels { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets list of provider channels.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "ProviderChannels", Justification = "Imported from ServiceStack")]
|
||||
public List<NameIdPair> ProviderChannels { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets list of mappings.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:DontReturnArrays", MessageId = "Mappings", Justification = "Imported from ServiceStack")]
|
||||
public NameValuePair[] Mappings { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets provider name.
|
||||
/// </summary>
|
||||
public string? ProviderName { get; set; }
|
||||
}
|
||||
}
|
166
Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
Normal file
166
Jellyfin.Api/Models/LiveTvDtos/GetProgramsDto.cs
Normal file
|
@ -0,0 +1,166 @@
|
|||
using System;
|
||||
|
||||
namespace Jellyfin.Api.Models.LiveTvDtos
|
||||
{
|
||||
/// <summary>
|
||||
/// Get programs dto.
|
||||
/// </summary>
|
||||
public class GetProgramsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the channels to return guide information for.
|
||||
/// </summary>
|
||||
public string? ChannelIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets optional. Filter by user id.
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum premiere start date.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public DateTime? MinStartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter by programs that have completed airing, or not.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? HasAired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter by programs that are currently airing, or not.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsAiring { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum premiere start date.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public DateTime? MaxStartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum premiere end date.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public DateTime? MinEndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum premiere end date.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public DateTime? MaxEndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter for movies.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsMovie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter for series.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter for news.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsNews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter for kids.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsKids { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter for sports.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? IsSports { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the record index to start at. All items with a lower index will be dropped from the results.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public int? StartIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of records to return.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public int? Limit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets specify one or more sort orders, comma delimited. Options: Name, StartDate.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public string? SortBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets sort Order - Ascending,Descending.
|
||||
/// </summary>
|
||||
public string? SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the genres to return guide information for.
|
||||
/// </summary>
|
||||
public string? Genres { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the genre ids to return guide information for.
|
||||
/// </summary>
|
||||
public string? GenreIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets include image information in output.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether retrieve total record count.
|
||||
/// </summary>
|
||||
public bool EnableTotalRecordCount { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max number of images to return, per image type.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public int? ImageTypeLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image types to include in the output.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public string? EnableImageTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets include user data.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public bool? EnableUserData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter by series timer id.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public string? SeriesTimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets filter by library series id.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public Guid LibrarySeriesId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets specify additional fields of information to return in the output. This allows multiple, comma delimited. Options: Budget, Chapters, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines.
|
||||
/// Optional.
|
||||
/// </summary>
|
||||
public string? Fields { get; set; }
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,80 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Api.LiveTv
|
||||
{
|
||||
public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _path;
|
||||
private readonly Dictionary<string, string> _outputHeaders;
|
||||
|
||||
public bool AllowEndOfFile = true;
|
||||
|
||||
private readonly IDirectStreamProvider _directStreamProvider;
|
||||
private IStreamHelper _streamHelper;
|
||||
|
||||
public ProgressiveFileCopier(IStreamHelper streamHelper, string path, Dictionary<string, string> outputHeaders, ILogger logger)
|
||||
{
|
||||
_path = path;
|
||||
_outputHeaders = outputHeaders;
|
||||
_logger = logger;
|
||||
_streamHelper = streamHelper;
|
||||
}
|
||||
|
||||
public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary<string, string> outputHeaders, ILogger logger)
|
||||
{
|
||||
_directStreamProvider = directStreamProvider;
|
||||
_outputHeaders = outputHeaders;
|
||||
_logger = logger;
|
||||
_streamHelper = streamHelper;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Headers => _outputHeaders;
|
||||
|
||||
public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_directStreamProvider != null)
|
||||
{
|
||||
await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var fileOptions = FileOptions.SequentialScan;
|
||||
|
||||
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
|
||||
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
|
||||
{
|
||||
fileOptions |= FileOptions.Asynchronous;
|
||||
}
|
||||
|
||||
using (var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions))
|
||||
{
|
||||
var emptyReadLimit = AllowEndOfFile ? 20 : 100;
|
||||
var eofCount = 0;
|
||||
while (eofCount < emptyReadLimit)
|
||||
{
|
||||
int bytesRead;
|
||||
bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
eofCount++;
|
||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
eofCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user