mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-05 05:42:52 +01:00
restored live tv playback in the web client
This commit is contained in:
@@ -103,6 +103,7 @@
|
||||
<Compile Include="Playback\Hls\DynamicHlsService.cs" />
|
||||
<Compile Include="Playback\Hls\HlsSegmentService.cs" />
|
||||
<Compile Include="Playback\Hls\VideoHlsService.cs" />
|
||||
<Compile Include="Playback\ProgressiveStreamService.cs" />
|
||||
<Compile Include="Playback\Progressive\AudioService.cs" />
|
||||
<Compile Include="Playback\Progressive\BaseProgressiveStreamingService.cs" />
|
||||
<Compile Include="Playback\BaseStreamingService.cs" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -36,103 +36,74 @@ namespace MediaBrowser.Api.Music
|
||||
public class InstantMixService : BaseApiService
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IMusicManager _musicManager;
|
||||
|
||||
public InstantMixService(IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService)
|
||||
public InstantMixService(IUserManager userManager, IDtoService dtoService, IMusicManager musicManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_musicManager = musicManager;
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromSong request)
|
||||
{
|
||||
var item = _dtoService.GetItemByDtoId(request.Id);
|
||||
var item = (Audio)_dtoService.GetItemByDtoId(request.Id);
|
||||
|
||||
var result = GetInstantMixResult(request, item.Genres);
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
var items = _musicManager.GetInstantMixFromSong(item, user);
|
||||
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromAlbum request)
|
||||
{
|
||||
var album = (MusicAlbum)_dtoService.GetItemByDtoId(request.Id);
|
||||
|
||||
var genres = album
|
||||
.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i => i.Genres)
|
||||
.Concat(album.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
var result = GetInstantMixResult(request, genres);
|
||||
var items = _musicManager.GetInstantMixFromAlbum(album, user);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromMusicGenre request)
|
||||
{
|
||||
var genre = GetMusicGenre(request.Name, _libraryManager);
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
var result = GetInstantMixResult(request, new[] { genre.Name });
|
||||
var items = _musicManager.GetInstantMixFromGenres(new[] { request.Name }, user);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
||||
public object Get(GetInstantMixFromArtist request)
|
||||
{
|
||||
var artist = GetArtist(request.Name, _libraryManager);
|
||||
var user = _userManager.GetUserById(request.UserId.Value);
|
||||
|
||||
var genres = _libraryManager.RootFolder
|
||||
.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.Where(i => i.HasArtist(artist.Name))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Concat(artist.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
var items = _musicManager.GetInstantMixFromArtist(request.Name, user);
|
||||
|
||||
var result = GetInstantMixResult(request, genres);
|
||||
|
||||
return ToOptimizedSerializedResultUsingCache(result);
|
||||
return GetResult(items, user, request);
|
||||
}
|
||||
|
||||
private ItemsResult GetInstantMixResult(BaseGetSimilarItems request, IEnumerable<string> genres)
|
||||
private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
|
||||
{
|
||||
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
|
||||
|
||||
var fields = request.GetItemFields().ToList();
|
||||
|
||||
var inputItems = user == null
|
||||
? _libraryManager.RootFolder.RecursiveChildren
|
||||
: user.RootFolder.GetRecursiveChildren(user);
|
||||
|
||||
var genresDictionary = genres.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var limit = request.Limit.HasValue ? request.Limit.Value * 2 : 100;
|
||||
|
||||
var items = inputItems
|
||||
.OfType<Audio>()
|
||||
.Select(i => new Tuple<Audio, int>(i, i.Genres.Count(genresDictionary.ContainsKey)))
|
||||
.OrderByDescending(i => i.Item2)
|
||||
.ThenBy(i => Guid.NewGuid())
|
||||
.Select(i => i.Item1)
|
||||
.Take(limit)
|
||||
.OrderBy(i => Guid.NewGuid())
|
||||
.ToList();
|
||||
var list = items.ToList();
|
||||
|
||||
var result = new ItemsResult
|
||||
{
|
||||
TotalRecordCount = items.Count
|
||||
TotalRecordCount = list.Count
|
||||
};
|
||||
|
||||
var dtos = items.Take(request.Limit ?? items.Count)
|
||||
var dtos = list.Take(request.Limit ?? list.Count)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
||||
|
||||
result.Items = dtos.ToArray();
|
||||
|
||||
return result;
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -835,11 +835,6 @@ namespace MediaBrowser.Api.Playback
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetInputArgument(StreamState state)
|
||||
{
|
||||
if (state.SendInputOverStandardInput)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
|
||||
var type = InputType.File;
|
||||
|
||||
var inputPath = new[] { state.MediaPath };
|
||||
@@ -898,9 +893,7 @@ namespace MediaBrowser.Api.Playback
|
||||
Arguments = commandLineArgs,
|
||||
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false,
|
||||
|
||||
RedirectStandardInput = state.SendInputOverStandardInput
|
||||
ErrorDialog = false
|
||||
},
|
||||
|
||||
EnableRaisingEvents = true
|
||||
@@ -933,11 +926,6 @@ namespace MediaBrowser.Api.Playback
|
||||
throw;
|
||||
}
|
||||
|
||||
if (state.SendInputOverStandardInput)
|
||||
{
|
||||
StreamToStandardInput(process, state);
|
||||
}
|
||||
|
||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
@@ -965,32 +953,6 @@ namespace MediaBrowser.Api.Playback
|
||||
}
|
||||
}
|
||||
|
||||
private async void StreamToStandardInput(Process process, StreamState state)
|
||||
{
|
||||
try
|
||||
{
|
||||
await StreamToStandardInputInternal(process, state).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Logger.Debug("Stream to standard input closed normally.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error writing to standard input", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StreamToStandardInputInternal(Process process, StreamState state)
|
||||
{
|
||||
state.StandardInputCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
using (var fileStream = FileSystem.GetFileStream(state.MediaPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||
{
|
||||
await new EndlessStreamCopy().CopyStream(fileStream, process.StandardInput.BaseStream, state.StandardInputCancellationTokenSource.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected int? GetVideoBitrateParamValue(StreamState state)
|
||||
{
|
||||
var bitrate = state.VideoRequest.VideoBitRate;
|
||||
@@ -1315,11 +1277,6 @@ namespace MediaBrowser.Api.Playback
|
||||
ParseParams(request);
|
||||
}
|
||||
|
||||
if (request.ThrowDebugError)
|
||||
{
|
||||
throw new InvalidOperationException("You asked for a debug error, you got one.");
|
||||
}
|
||||
|
||||
var user = AuthorizationRequestFilterAttribute.GetCurrentUser(Request, UserManager);
|
||||
|
||||
var url = Request.PathInfo;
|
||||
@@ -1369,8 +1326,6 @@ namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
state.MediaPath = path;
|
||||
state.IsRemote = false;
|
||||
|
||||
state.SendInputOverStandardInput = recording.RecordingInfo.Status == RecordingStatus.InProgress;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(mediaUrl))
|
||||
{
|
||||
@@ -1378,7 +1333,8 @@ namespace MediaBrowser.Api.Playback
|
||||
state.IsRemote = true;
|
||||
}
|
||||
|
||||
//state.RunTimeTicks = recording.RunTimeTicks;
|
||||
state.RunTimeTicks = recording.RunTimeTicks;
|
||||
|
||||
if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsRemote)
|
||||
{
|
||||
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
73
MediaBrowser.Api/Playback/ProgressiveStreamService.cs
Normal file
73
MediaBrowser.Api/Playback/ProgressiveStreamService.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Api.Playback.Progressive;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
//public class GetProgressiveAudioStream : StreamRequest
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
//public class ProgressiveStreamService : BaseApiService
|
||||
//{
|
||||
// public object Get(GetProgressiveAudioStream request)
|
||||
// {
|
||||
// return ProcessRequest(request, false);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Gets the specified request.
|
||||
// /// </summary>
|
||||
// /// <param name="request">The request.</param>
|
||||
// /// <returns>System.Object.</returns>
|
||||
// public object Head(GetProgressiveAudioStream request)
|
||||
// {
|
||||
// return ProcessRequest(request, true);
|
||||
// }
|
||||
|
||||
// protected object ProcessRequest(StreamRequest request, bool isHeadRequest)
|
||||
// {
|
||||
// var state = GetState(request, CancellationToken.None).Result;
|
||||
|
||||
// var responseHeaders = new Dictionary<string, string>();
|
||||
|
||||
// if (request.Static && state.IsRemote)
|
||||
// {
|
||||
// AddDlnaHeaders(state, responseHeaders, true);
|
||||
|
||||
// return GetStaticRemoteStreamResult(state.MediaPath, responseHeaders, isHeadRequest).Result;
|
||||
// }
|
||||
|
||||
// var outputPath = GetOutputFilePath(state);
|
||||
// var outputPathExists = File.Exists(outputPath);
|
||||
|
||||
// var isStatic = request.Static ||
|
||||
// (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive));
|
||||
|
||||
// AddDlnaHeaders(state, responseHeaders, isStatic);
|
||||
|
||||
// if (request.Static)
|
||||
// {
|
||||
// var contentType = state.GetMimeType(state.MediaPath);
|
||||
|
||||
// return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
// }
|
||||
|
||||
// if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
|
||||
// {
|
||||
// var contentType = state.GetMimeType(outputPath);
|
||||
|
||||
// return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
// }
|
||||
|
||||
// return GetStreamResult(state, responseHeaders, isHeadRequest).Result;
|
||||
// }
|
||||
|
||||
//}
|
||||
}
|
||||
@@ -67,11 +67,6 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
[ApiMember(Name = "DeviceProfileId", Description = "Optional. The dlna device profile id to utilize.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string DeviceProfileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For testing purposes
|
||||
/// </summary>
|
||||
public bool ThrowDebugError { get; set; }
|
||||
|
||||
public string Params { get; set; }
|
||||
}
|
||||
|
||||
@@ -51,8 +51,6 @@ namespace MediaBrowser.Api.Playback
|
||||
|
||||
public bool HasMediaStreams { get; set; }
|
||||
|
||||
public bool SendInputOverStandardInput { get; set; }
|
||||
|
||||
public CancellationTokenSource StandardInputCancellationTokenSource { get; set; }
|
||||
|
||||
public string LiveTvStreamId { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user