channel fixes
This commit is contained in:
parent
ca5989cb17
commit
3ccecd3ca3
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -25,7 +26,6 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
protected IItemRepository ItemRepository { get; private set; }
|
protected IItemRepository ItemRepository { get; private set; }
|
||||||
protected ILiveTvManager LiveTvManager { get; private set; }
|
protected ILiveTvManager LiveTvManager { get; private set; }
|
||||||
protected IDlnaManager DlnaManager { get; private set; }
|
protected IDlnaManager DlnaManager { get; private set; }
|
||||||
|
protected IChannelManager ChannelManager { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||||
|
@ -83,8 +84,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <param name="dtoService">The dto service.</param>
|
/// <param name="dtoService">The dto service.</param>
|
||||||
/// <param name="fileSystem">The file system.</param>
|
/// <param name="fileSystem">The file system.</param>
|
||||||
/// <param name="itemRepository">The item repository.</param>
|
/// <param name="itemRepository">The item repository.</param>
|
||||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
|
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager)
|
||||||
{
|
{
|
||||||
|
ChannelManager = channelManager;
|
||||||
DlnaManager = dlnaManager;
|
DlnaManager = dlnaManager;
|
||||||
EncodingManager = encodingManager;
|
EncodingManager = encodingManager;
|
||||||
LiveTvManager = liveTvManager;
|
LiveTvManager = liveTvManager;
|
||||||
|
@ -169,13 +171,28 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected virtual string GetMapArgs(StreamState state)
|
protected virtual string GetMapArgs(StreamState state)
|
||||||
{
|
{
|
||||||
var args = string.Empty;
|
// If we don't have known media info
|
||||||
|
// If input is video, use -sn to drop subtitles
|
||||||
if (!state.HasMediaStreams)
|
// Otherwise just return empty
|
||||||
|
if (state.VideoStream == null && state.AudioStream == null)
|
||||||
{
|
{
|
||||||
return state.IsInputVideo ? "-sn" : string.Empty;
|
return state.IsInputVideo ? "-sn" : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have media info, but we don't know the stream indexes
|
||||||
|
if (state.VideoStream != null && state.VideoStream.Index == -1)
|
||||||
|
{
|
||||||
|
return "-sn";
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have media info, but we don't know the stream indexes
|
||||||
|
if (state.AudioStream != null && state.AudioStream.Index == -1)
|
||||||
|
{
|
||||||
|
return state.IsInputVideo ? "-sn" : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = string.Empty;
|
||||||
|
|
||||||
if (state.VideoStream != null)
|
if (state.VideoStream != null)
|
||||||
{
|
{
|
||||||
args += string.Format("-map 0:{0}", state.VideoStream.Index);
|
args += string.Format("-map 0:{0}", state.VideoStream.Index);
|
||||||
|
@ -1329,13 +1346,14 @@ namespace MediaBrowser.Api.Playback
|
||||||
throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
|
throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<MediaStream> mediaStreams = null;
|
||||||
|
|
||||||
if (item is ILiveTvRecording)
|
if (item is ILiveTvRecording)
|
||||||
{
|
{
|
||||||
var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
|
var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
state.VideoType = VideoType.VideoFile;
|
state.VideoType = VideoType.VideoFile;
|
||||||
state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
state.PlayableStreamFileNames = new List<string>();
|
|
||||||
|
|
||||||
var path = recording.RecordingInfo.Path;
|
var path = recording.RecordingInfo.Path;
|
||||||
var mediaUrl = recording.RecordingInfo.Url;
|
var mediaUrl = recording.RecordingInfo.Url;
|
||||||
|
@ -1345,6 +1363,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
|
var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
state.LiveTvStreamId = streamInfo.Id;
|
state.LiveTvStreamId = streamInfo.Id;
|
||||||
|
mediaStreams = streamInfo.MediaStreams;
|
||||||
|
|
||||||
path = streamInfo.Path;
|
path = streamInfo.Path;
|
||||||
mediaUrl = streamInfo.Url;
|
mediaUrl = streamInfo.Url;
|
||||||
|
@ -1381,11 +1400,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
state.VideoType = VideoType.VideoFile;
|
state.VideoType = VideoType.VideoFile;
|
||||||
state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
state.PlayableStreamFileNames = new List<string>();
|
|
||||||
|
|
||||||
var streamInfo = await LiveTvManager.GetChannelStream(request.Id, cancellationToken).ConfigureAwait(false);
|
var streamInfo = await LiveTvManager.GetChannelStream(request.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
state.LiveTvStreamId = streamInfo.Id;
|
state.LiveTvStreamId = streamInfo.Id;
|
||||||
|
mediaStreams = streamInfo.MediaStreams;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(streamInfo.Path))
|
if (!string.IsNullOrEmpty(streamInfo.Path))
|
||||||
{
|
{
|
||||||
|
@ -1406,6 +1425,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
state.InputVideoSync = "-1";
|
state.InputVideoSync = "-1";
|
||||||
state.InputAudioSync = "1";
|
state.InputAudioSync = "1";
|
||||||
}
|
}
|
||||||
|
else if (item is IChannelMediaItem)
|
||||||
|
{
|
||||||
|
var channelMediaSources = await ChannelManager.GetChannelItemMediaSources(request.Id, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var source = channelMediaSources.First();
|
||||||
|
state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
|
||||||
|
state.IsRemote = source.IsRemote;
|
||||||
|
state.MediaPath = source.Path;
|
||||||
|
state.RunTimeTicks = item.RunTimeTicks;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.MediaPath = item.Path;
|
state.MediaPath = item.Path;
|
||||||
|
@ -1424,7 +1453,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
: video.PlayableStreamFileNames.ToList();
|
: video.PlayableStreamFileNames.ToList();
|
||||||
|
|
||||||
state.DeInterlace = string.Equals(video.Container, "wtv", StringComparison.OrdinalIgnoreCase);
|
state.DeInterlace = string.Equals(video.Container, "wtv", StringComparison.OrdinalIgnoreCase);
|
||||||
state.InputTimestamp = video.Timestamp ?? TransportStreamTimestamp.None;
|
|
||||||
|
if (video.Timestamp.HasValue)
|
||||||
|
{
|
||||||
|
state.InputTimestamp = video.Timestamp.Value;
|
||||||
|
}
|
||||||
|
|
||||||
state.InputContainer = video.Container;
|
state.InputContainer = video.Container;
|
||||||
}
|
}
|
||||||
|
@ -1440,7 +1473,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var videoRequest = request as VideoStreamRequest;
|
var videoRequest = request as VideoStreamRequest;
|
||||||
|
|
||||||
var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
|
mediaStreams = mediaStreams ?? ItemRepository.GetMediaStreams(new MediaStreamQuery
|
||||||
{
|
{
|
||||||
ItemId = item.Id
|
ItemId = item.Id
|
||||||
|
|
||||||
|
@ -1469,8 +1502,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
|
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.HasMediaStreams = mediaStreams.Count > 0;
|
|
||||||
|
|
||||||
state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
|
state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
|
||||||
state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
|
state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -24,8 +25,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseHlsService : BaseStreamingService
|
public abstract class BaseHlsService : BaseStreamingService
|
||||||
{
|
{
|
||||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
|
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -59,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
public class DynamicHlsService : BaseHlsService
|
public class DynamicHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoHlsService : BaseHlsService
|
public class VideoHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -43,8 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioService : BaseProgressiveStreamingService
|
public class AudioService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
|
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager, imageProcessor, httpClient)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -26,11 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
protected readonly IImageProcessor ImageProcessor;
|
protected readonly IImageProcessor ImageProcessor;
|
||||||
protected readonly IHttpClient HttpClient;
|
protected readonly IHttpClient HttpClient;
|
||||||
|
|
||||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
|
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
|
||||||
: base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
|
|
||||||
{
|
{
|
||||||
HttpClient = httpClient;
|
|
||||||
ImageProcessor = imageProcessor;
|
ImageProcessor = imageProcessor;
|
||||||
|
HttpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
|
@ -59,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoService : BaseProgressiveStreamingService
|
public class VideoService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
|
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
private string GetAudioArguments(StreamState state)
|
private string GetAudioArguments(StreamState state)
|
||||||
{
|
{
|
||||||
// If the video doesn't have an audio stream, return a default.
|
// If the video doesn't have an audio stream, return a default.
|
||||||
if (state.AudioStream == null && state.HasMediaStreams)
|
if (state.AudioStream == null && state.VideoStream != null)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
get { return Request as VideoStreamRequest; }
|
get { return Request as VideoStreamRequest; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StreamState()
|
||||||
|
{
|
||||||
|
PlayableStreamFileNames = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the log file stream.
|
/// Gets or sets the log file stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -57,8 +62,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public List<string> PlayableStreamFileNames { get; set; }
|
public List<string> PlayableStreamFileNames { get; set; }
|
||||||
|
|
||||||
public bool HasMediaStreams { get; set; }
|
|
||||||
|
|
||||||
public string LiveTvStreamId { get; set; }
|
public string LiveTvStreamId { get; set; }
|
||||||
|
|
||||||
public int SegmentLength = 10;
|
public int SegmentLength = 10;
|
||||||
|
|
|
@ -218,6 +218,9 @@ namespace MediaBrowser.Api
|
||||||
[ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
[ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||||
public string SupportedCommands { get; set; }
|
public string SupportedCommands { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "MessageCallbackUrl", Description = "A url to post messages to, including remote control commands.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||||
|
public string MessageCallbackUrl { get; set; }
|
||||||
|
|
||||||
[ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
[ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
|
||||||
public bool SupportsMediaControl { get; set; }
|
public bool SupportsMediaControl { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -414,7 +417,9 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
|
SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
|
||||||
|
|
||||||
SupportsMediaControl = request.SupportsMediaControl
|
SupportsMediaControl = request.SupportsMediaControl,
|
||||||
|
|
||||||
|
MessageCallbackUrl = request.MessageCallbackUrl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Linq;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
|
@ -18,6 +20,8 @@ namespace MediaBrowser.Controller.Channels
|
||||||
|
|
||||||
public string OriginalImageUrl { get; set; }
|
public string OriginalImageUrl { get; set; }
|
||||||
|
|
||||||
|
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||||
{
|
{
|
||||||
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
|
||||||
|
@ -30,5 +34,23 @@ namespace MediaBrowser.Controller.Channels
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChannelAudioItem()
|
||||||
|
{
|
||||||
|
ChannelMediaSources = new List<ChannelMediaInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override LocationType LocationType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path))
|
||||||
|
{
|
||||||
|
return LocationType.Remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.LocationType;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
|
@ -12,6 +13,7 @@ namespace MediaBrowser.Controller.Channels
|
||||||
public ChannelItemType ChannelItemType { get; set; }
|
public ChannelItemType ChannelItemType { get; set; }
|
||||||
|
|
||||||
public string OriginalImageUrl { get; set; }
|
public string OriginalImageUrl { get; set; }
|
||||||
|
public List<string> Tags { get; set; }
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||||
{
|
{
|
||||||
|
@ -26,5 +28,10 @@ namespace MediaBrowser.Controller.Channels
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChannelCategoryItem()
|
||||||
|
{
|
||||||
|
Tags = new List<string>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Channels
|
||||||
|
|
||||||
public List<string> Genres { get; set; }
|
public List<string> Genres { get; set; }
|
||||||
public List<string> Studios { get; set; }
|
public List<string> Studios { get; set; }
|
||||||
|
public List<string> Tags { get; set; }
|
||||||
|
|
||||||
public List<PersonInfo> People { get; set; }
|
public List<PersonInfo> People { get; set; }
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ namespace MediaBrowser.Controller.Channels
|
||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
Studios = new List<string>();
|
Studios = new List<string>();
|
||||||
People = new List<PersonInfo>();
|
People = new List<PersonInfo>();
|
||||||
|
Tags = new List<string>();
|
||||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,12 @@ namespace MediaBrowser.Controller.Channels
|
||||||
public int? Height { get; set; }
|
public int? Height { get; set; }
|
||||||
public int? AudioChannels { get; set; }
|
public int? AudioChannels { get; set; }
|
||||||
|
|
||||||
|
public bool IsRemote { get; set; }
|
||||||
|
|
||||||
public ChannelMediaInfo()
|
public ChannelMediaInfo()
|
||||||
{
|
{
|
||||||
RequiredHttpHeaders = new Dictionary<string, string>();
|
RequiredHttpHeaders = new Dictionary<string, string>();
|
||||||
|
IsRemote = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -20,6 +21,8 @@ namespace MediaBrowser.Controller.Channels
|
||||||
|
|
||||||
public string OriginalImageUrl { get; set; }
|
public string OriginalImageUrl { get; set; }
|
||||||
|
|
||||||
|
public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||||
|
|
||||||
public override string GetUserDataKey()
|
public override string GetUserDataKey()
|
||||||
{
|
{
|
||||||
if (ContentType == ChannelMediaContentType.Trailer)
|
if (ContentType == ChannelMediaContentType.Trailer)
|
||||||
|
@ -55,5 +58,23 @@ namespace MediaBrowser.Controller.Channels
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChannelVideoItem()
|
||||||
|
{
|
||||||
|
ChannelMediaSources = new List<ChannelMediaInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override LocationType LocationType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path))
|
||||||
|
{
|
||||||
|
return LocationType.Remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.LocationType;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,4 +59,15 @@ namespace MediaBrowser.Controller.Channels
|
||||||
/// <returns>IEnumerable{ImageType}.</returns>
|
/// <returns>IEnumerable{ImageType}.</returns>
|
||||||
IEnumerable<ImageType> GetSupportedChannelImages();
|
IEnumerable<ImageType> GetSupportedChannelImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IRequiresMediaInfoCallback
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel item media information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{ChannelMediaInfo}}.</returns>
|
||||||
|
Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaInfo(string id, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Channels
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
public interface IChannelItem : IHasImages
|
public interface IChannelItem : IHasImages, IHasTags
|
||||||
{
|
{
|
||||||
string ChannelId { get; set; }
|
string ChannelId { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -31,5 +31,13 @@ namespace MediaBrowser.Controller.Channels
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
||||||
Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken);
|
Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the channel item media sources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{IEnumerable{ChannelMediaInfo}}.</returns>
|
||||||
|
Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaSources(string id, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
namespace MediaBrowser.Controller.Channels
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Channels
|
||||||
{
|
{
|
||||||
public interface IChannelMediaItem : IChannelItem
|
public interface IChannelMediaItem : IChannelItem
|
||||||
{
|
{
|
||||||
bool IsInfiniteStream { get; set; }
|
bool IsInfiniteStream { get; set; }
|
||||||
|
|
||||||
ChannelMediaContentType ContentType { get; set; }
|
ChannelMediaContentType ContentType { get; set; }
|
||||||
|
|
||||||
|
List<ChannelMediaInfo> ChannelMediaSources { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,16 +10,18 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class Audio
|
/// Class Audio
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<SongInfo>
|
public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<SongInfo>, IHasTags
|
||||||
{
|
{
|
||||||
public string FormatName { get; set; }
|
public string FormatName { get; set; }
|
||||||
public long? Size { get; set; }
|
public long? Size { get; set; }
|
||||||
public string Container { get; set; }
|
public string Container { get; set; }
|
||||||
public int? TotalBitrate { get; set; }
|
public int? TotalBitrate { get; set; }
|
||||||
|
public List<string> Tags { get; set; }
|
||||||
|
|
||||||
public Audio()
|
public Audio()
|
||||||
{
|
{
|
||||||
Artists = new List<string>();
|
Artists = new List<string>();
|
||||||
|
Tags = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Session;
|
using MediaBrowser.Model.Session;
|
||||||
|
using MediaBrowser.Model.System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -54,9 +55,10 @@ namespace MediaBrowser.Controller.Session
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the restart required message.
|
/// Sends the restart required message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="info">The information.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task SendRestartRequiredNotification(CancellationToken cancellationToken);
|
Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the user data change info.
|
/// Sends the user data change info.
|
||||||
|
|
|
@ -19,6 +19,7 @@ using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.System;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -320,7 +321,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
|
||||||
{
|
|
||||||
public class AudioEncoder
|
|
||||||
{
|
|
||||||
private readonly string _ffmpegPath;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
|
||||||
private readonly IIsoManager _isoManager;
|
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
public AudioEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths, IIsoManager isoManager, ILiveTvManager liveTvManager)
|
|
||||||
{
|
|
||||||
_ffmpegPath = ffmpegPath;
|
|
||||||
_logger = logger;
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_appPaths = appPaths;
|
|
||||||
_isoManager = isoManager;
|
|
||||||
_liveTvManager = liveTvManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task BeginEncoding(InternalEncodingTask task)
|
|
||||||
{
|
|
||||||
return new FFMpegProcess(_ffmpegPath, _logger, _fileSystem, _appPaths, _isoManager, _liveTvManager).Start(task, GetArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetArguments(InternalEncodingTask task, string mountedPath)
|
|
||||||
{
|
|
||||||
var options = task.Request;
|
|
||||||
|
|
||||||
return string.Format("{0} -i {1} {2} -id3v2_version 3 -write_id3v1 1 \"{3}\"",
|
|
||||||
GetInputModifier(task),
|
|
||||||
GetInputArgument(task),
|
|
||||||
GetOutputModifier(task),
|
|
||||||
options.OutputPath).Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetInputModifier(InternalEncodingTask task)
|
|
||||||
{
|
|
||||||
return EncodingUtils.GetInputModifier(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetInputArgument(InternalEncodingTask task)
|
|
||||||
{
|
|
||||||
return EncodingUtils.GetInputArgument(new List<string> { task.MediaPath }, task.IsInputRemote);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetOutputModifier(InternalEncodingTask task)
|
|
||||||
{
|
|
||||||
var options = task.Request;
|
|
||||||
|
|
||||||
var audioTranscodeParams = new List<string>
|
|
||||||
{
|
|
||||||
"-threads " + EncodingUtils.GetNumberOfThreads(task, false).ToString(_usCulture),
|
|
||||||
"-vn"
|
|
||||||
};
|
|
||||||
|
|
||||||
var bitrate = EncodingUtils.GetAudioBitrateParam(task);
|
|
||||||
|
|
||||||
if (bitrate.HasValue)
|
|
||||||
{
|
|
||||||
audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(_usCulture));
|
|
||||||
}
|
|
||||||
|
|
||||||
var channels = EncodingUtils.GetNumAudioChannelsParam(options, task.AudioStream);
|
|
||||||
|
|
||||||
if (channels.HasValue)
|
|
||||||
{
|
|
||||||
audioTranscodeParams.Add("-ac " + channels.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.AudioSampleRate.HasValue)
|
|
||||||
{
|
|
||||||
audioTranscodeParams.Add("-ar " + options.AudioSampleRate.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Join(" ", audioTranscodeParams.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -64,77 +64,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return string.Format("\"{0}\"", url);
|
return string.Format("\"{0}\"", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetAudioInputModifier(InternalEncodingTask options)
|
|
||||||
{
|
|
||||||
return GetCommonInputModifier(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetInputModifier(InternalEncodingTask options)
|
|
||||||
{
|
|
||||||
var inputModifier = GetCommonInputModifier(options);
|
|
||||||
|
|
||||||
//if (state.VideoRequest != null)
|
|
||||||
//{
|
|
||||||
// inputModifier += " -fflags genpts";
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if (!string.IsNullOrEmpty(state.InputVideoCodec))
|
|
||||||
//{
|
|
||||||
// inputModifier += " -vcodec " + state.InputVideoCodec;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if (!string.IsNullOrEmpty(state.InputVideoSync))
|
|
||||||
//{
|
|
||||||
// inputModifier += " -vsync " + state.InputVideoSync;
|
|
||||||
//}
|
|
||||||
|
|
||||||
return inputModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCommonInputModifier(InternalEncodingTask options)
|
|
||||||
{
|
|
||||||
var inputModifier = string.Empty;
|
|
||||||
|
|
||||||
if (options.EnableDebugLogging)
|
|
||||||
{
|
|
||||||
inputModifier += "-loglevel debug";
|
|
||||||
}
|
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(options.InputVideoType.HasValue && options.InputVideoType.Value == VideoType.Dvd);
|
|
||||||
inputModifier += " " + probeSize;
|
|
||||||
inputModifier = inputModifier.Trim();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(options.UserAgent))
|
|
||||||
{
|
|
||||||
inputModifier += " -user-agent \"" + options.UserAgent + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
inputModifier += " " + GetFastSeekValue(options.Request);
|
|
||||||
inputModifier = inputModifier.Trim();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.InputFormat))
|
|
||||||
{
|
|
||||||
inputModifier += " -f " + options.InputFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.InputAudioCodec))
|
|
||||||
{
|
|
||||||
inputModifier += " -acodec " + options.InputAudioCodec;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.InputAudioSync))
|
|
||||||
{
|
|
||||||
inputModifier += " -async " + options.InputAudioSync;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ReadInputAtNativeFramerate)
|
|
||||||
{
|
|
||||||
inputModifier += " -re";
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFastSeekValue(EncodingOptions options)
|
private static string GetFastSeekValue(EncodingOptions options)
|
||||||
{
|
{
|
||||||
var time = options.StartTimeTicks;
|
var time = options.StartTimeTicks;
|
||||||
|
@ -157,19 +86,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
|
return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int? GetAudioBitrateParam(InternalEncodingTask task)
|
|
||||||
{
|
|
||||||
if (task.Request.AudioBitRate.HasValue)
|
|
||||||
{
|
|
||||||
// Make sure we don't request a bitrate higher than the source
|
|
||||||
var currentBitrate = task.AudioStream == null ? task.Request.AudioBitRate.Value : task.AudioStream.BitRate ?? task.Request.AudioBitRate.Value;
|
|
||||||
|
|
||||||
return Math.Min(currentBitrate, task.Request.AudioBitRate.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of audio channels to specify on the command line
|
/// Gets the number of audio channels to specify on the command line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -201,35 +117,5 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
return request.AudioChannels;
|
return request.AudioChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetNumberOfThreads(InternalEncodingTask state, bool isWebm)
|
|
||||||
{
|
|
||||||
// Use more when this is true. -re will keep cpu usage under control
|
|
||||||
if (state.ReadInputAtNativeFramerate)
|
|
||||||
{
|
|
||||||
if (isWebm)
|
|
||||||
{
|
|
||||||
return Math.Max(Environment.ProcessorCount - 1, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Webm: http://www.webmproject.org/docs/encoder-parameters/
|
|
||||||
// The decoder will usually automatically use an appropriate number of threads according to how many cores are available but it can only use multiple threads
|
|
||||||
// for the coefficient data if the encoder selected --token-parts > 0 at encode time.
|
|
||||||
|
|
||||||
switch (state.QualitySetting)
|
|
||||||
{
|
|
||||||
case EncodingQuality.HighSpeed:
|
|
||||||
return 2;
|
|
||||||
case EncodingQuality.HighQuality:
|
|
||||||
return 2;
|
|
||||||
case EncodingQuality.MaxQuality:
|
|
||||||
return isWebm ? Math.Max(Environment.ProcessorCount - 1, 2) : 0;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unrecognized MediaEncodingQuality value.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
|
||||||
{
|
|
||||||
public class FFMpegProcess : IDisposable
|
|
||||||
{
|
|
||||||
private readonly string _ffmpegPath;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
|
||||||
private readonly IIsoManager _isoManager;
|
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
|
||||||
|
|
||||||
private Stream _logFileStream;
|
|
||||||
private InternalEncodingTask _task;
|
|
||||||
private IIsoMount _isoMount;
|
|
||||||
|
|
||||||
public FFMpegProcess(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths, IIsoManager isoManager, ILiveTvManager liveTvManager)
|
|
||||||
{
|
|
||||||
_ffmpegPath = ffmpegPath;
|
|
||||||
_logger = logger;
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_appPaths = appPaths;
|
|
||||||
_isoManager = isoManager;
|
|
||||||
_liveTvManager = liveTvManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Start(InternalEncodingTask task, Func<InternalEncodingTask,string,string> argumentsFactory)
|
|
||||||
{
|
|
||||||
_task = task;
|
|
||||||
if (!File.Exists(_ffmpegPath))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("ffmpeg was not found at " + _ffmpegPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(task.Request.OutputPath));
|
|
||||||
|
|
||||||
string mountedPath = null;
|
|
||||||
if (task.InputVideoType.HasValue && task.InputVideoType == VideoType.Iso && task.IsoType.HasValue)
|
|
||||||
{
|
|
||||||
if (_isoManager.CanMount(task.MediaPath))
|
|
||||||
{
|
|
||||||
_isoMount = await _isoManager.Mount(task.MediaPath, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
mountedPath = _isoMount.MountedPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
CreateNoWindow = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
|
|
||||||
// Must consume both stdout and stderr or deadlocks may occur
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
|
|
||||||
FileName = _ffmpegPath,
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(_ffmpegPath),
|
|
||||||
Arguments = argumentsFactory(task, mountedPath),
|
|
||||||
|
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
|
||||||
ErrorDialog = false
|
|
||||||
},
|
|
||||||
|
|
||||||
EnableRaisingEvents = true
|
|
||||||
};
|
|
||||||
|
|
||||||
_logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
|
||||||
|
|
||||||
var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-" + task.Id + ".txt");
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
|
|
||||||
|
|
||||||
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
|
|
||||||
_logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
|
|
||||||
|
|
||||||
process.Exited += process_Exited;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
process.Start();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error starting ffmpeg", ex);
|
|
||||||
|
|
||||||
task.OnError();
|
|
||||||
|
|
||||||
DisposeLogFileStream();
|
|
||||||
|
|
||||||
process.Dispose();
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
task.OnBegin();
|
|
||||||
|
|
||||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
|
||||||
process.BeginOutputReadLine();
|
|
||||||
|
|
||||||
#pragma warning disable 4014
|
|
||||||
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
|
||||||
process.StandardError.BaseStream.CopyToAsync(_logFileStream);
|
|
||||||
#pragma warning restore 4014
|
|
||||||
}
|
|
||||||
|
|
||||||
async void process_Exited(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var process = (Process)sender;
|
|
||||||
|
|
||||||
if (_isoMount != null)
|
|
||||||
{
|
|
||||||
_isoMount.Dispose();
|
|
||||||
_isoMount = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisposeLogFileStream();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("FFMpeg exited with code {0} for {1}", process.ExitCode, _task.Request.OutputPath);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
_logger.Info("FFMpeg exited with an error for {0}", _task.Request.OutputPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
_task.OnCompleted();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_task.LiveTvStreamId))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _liveTvManager.CloseLiveStream(_task.LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error closing live tv stream", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
DisposeLogFileStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DisposeLogFileStream()
|
|
||||||
{
|
|
||||||
if (_logFileStream != null)
|
|
||||||
{
|
|
||||||
_logFileStream.Dispose();
|
|
||||||
_logFileStream = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,235 +0,0 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
|
||||||
{
|
|
||||||
public class ImageEncoder
|
|
||||||
{
|
|
||||||
private readonly string _ffmpegPath;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IFileSystem _fileSystem;
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(10, 10);
|
|
||||||
|
|
||||||
public ImageEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths)
|
|
||||||
{
|
|
||||||
_ffmpegPath = ffmpegPath;
|
|
||||||
_logger = logger;
|
|
||||||
_fileSystem = fileSystem;
|
|
||||||
_appPaths = appPaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
ValidateInput(options);
|
|
||||||
|
|
||||||
await ResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await EncodeImageInternal(options, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ResourcePool.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<Stream> EncodeImageInternal(ImageEncodingOptions options, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
ValidateInput(options);
|
|
||||||
|
|
||||||
var inputPath = options.InputPath;
|
|
||||||
var filename = Path.GetFileName(inputPath);
|
|
||||||
|
|
||||||
if (HasDiacritics(filename))
|
|
||||||
{
|
|
||||||
inputPath = GetTempFile(inputPath);
|
|
||||||
filename = Path.GetFileName(inputPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var process = new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
CreateNoWindow = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
FileName = _ffmpegPath,
|
|
||||||
Arguments = GetArguments(options, filename),
|
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
|
||||||
ErrorDialog = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(inputPath)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_logger.Debug("ffmpeg " + process.StartInfo.Arguments);
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
#pragma warning disable 4014
|
|
||||||
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
|
||||||
process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
|
|
||||||
#pragma warning restore 4014
|
|
||||||
|
|
||||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
|
|
||||||
var ranToCompletion = process.WaitForExit(5000);
|
|
||||||
|
|
||||||
if (!ranToCompletion)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Killing ffmpeg process");
|
|
||||||
|
|
||||||
process.Kill();
|
|
||||||
|
|
||||||
process.WaitForExit(1000);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error killing process", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var exitCode = ranToCompletion ? process.ExitCode : -1;
|
|
||||||
|
|
||||||
process.Dispose();
|
|
||||||
|
|
||||||
if (exitCode == -1 || memoryStream.Length == 0)
|
|
||||||
{
|
|
||||||
memoryStream.Dispose();
|
|
||||||
|
|
||||||
var msg = string.Format("ffmpeg image encoding failed for {0}", options.InputPath);
|
|
||||||
|
|
||||||
_logger.Error(msg);
|
|
||||||
|
|
||||||
throw new ApplicationException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
return memoryStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetTempFile(string path)
|
|
||||||
{
|
|
||||||
var extension = Path.GetExtension(path) ?? string.Empty;
|
|
||||||
|
|
||||||
var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N") + extension);
|
|
||||||
|
|
||||||
File.Copy(path, tempPath);
|
|
||||||
|
|
||||||
return tempPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetArguments(ImageEncodingOptions options, string inputFilename)
|
|
||||||
{
|
|
||||||
var vfScale = GetFilterGraph(options);
|
|
||||||
var outputFormat = GetOutputFormat(options.Format);
|
|
||||||
|
|
||||||
var quality = (options.Quality ?? 100) * .3;
|
|
||||||
quality = 31 - quality;
|
|
||||||
var qualityValue = Convert.ToInt32(Math.Max(quality, 1));
|
|
||||||
|
|
||||||
return string.Format("-f image2 -i file:\"{3}\" -q:v {0} {1} -f image2pipe -vcodec {2} -",
|
|
||||||
qualityValue.ToString(_usCulture),
|
|
||||||
vfScale,
|
|
||||||
outputFormat,
|
|
||||||
inputFilename);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFilterGraph(ImageEncodingOptions options)
|
|
||||||
{
|
|
||||||
if (!options.Width.HasValue &&
|
|
||||||
!options.Height.HasValue &&
|
|
||||||
!options.MaxHeight.HasValue &&
|
|
||||||
!options.MaxWidth.HasValue)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var widthScale = "-1";
|
|
||||||
var heightScale = "-1";
|
|
||||||
|
|
||||||
if (options.MaxWidth.HasValue)
|
|
||||||
{
|
|
||||||
widthScale = "min(iw\\," + options.MaxWidth.Value.ToString(_usCulture) + ")";
|
|
||||||
}
|
|
||||||
else if (options.Width.HasValue)
|
|
||||||
{
|
|
||||||
widthScale = options.Width.Value.ToString(_usCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.MaxHeight.HasValue)
|
|
||||||
{
|
|
||||||
heightScale = "min(ih\\," + options.MaxHeight.Value.ToString(_usCulture) + ")";
|
|
||||||
}
|
|
||||||
else if (options.Height.HasValue)
|
|
||||||
{
|
|
||||||
heightScale = options.Height.Value.ToString(_usCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
var scaleMethod = "lanczos";
|
|
||||||
|
|
||||||
return string.Format("-vf scale=\"{0}:{1}\"",
|
|
||||||
widthScale,
|
|
||||||
heightScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetOutputFormat(string format)
|
|
||||||
{
|
|
||||||
if (string.Equals(format, "jpeg", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(format, "jpg", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return "mjpeg";
|
|
||||||
}
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateInput(ImageEncodingOptions options)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the specified text has diacritics.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The text.</param>
|
|
||||||
/// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
|
|
||||||
private bool HasDiacritics(string text)
|
|
||||||
{
|
|
||||||
return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the diacritics.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The text.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
|
||||||
private string RemoveDiacritics(string text)
|
|
||||||
{
|
|
||||||
return String.Concat(
|
|
||||||
text.Normalize(NormalizationForm.FormD)
|
|
||||||
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
|
|
||||||
UnicodeCategory.NonSpacingMark)
|
|
||||||
).Normalize(NormalizationForm.FormC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
|
||||||
{
|
|
||||||
public class InternalEncodingTask
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
public CancellationTokenSource CancellationTokenSource { get; set; }
|
|
||||||
|
|
||||||
public double ProgressPercentage { get; set; }
|
|
||||||
|
|
||||||
public EncodingOptions Request { get; set; }
|
|
||||||
|
|
||||||
public VideoEncodingOptions VideoRequest
|
|
||||||
{
|
|
||||||
get { return Request as VideoEncodingOptions; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string MediaPath { get; set; }
|
|
||||||
public List<string> StreamFileNames { get; set; }
|
|
||||||
public bool IsInputRemote { get; set; }
|
|
||||||
|
|
||||||
public VideoType? InputVideoType { get; set; }
|
|
||||||
public IsoType? IsoType { get; set; }
|
|
||||||
public long? InputRunTimeTicks;
|
|
||||||
|
|
||||||
public string AudioSync = "1";
|
|
||||||
public string VideoSync = "vfr";
|
|
||||||
|
|
||||||
public string InputAudioSync { get; set; }
|
|
||||||
public string InputVideoSync { get; set; }
|
|
||||||
|
|
||||||
public bool DeInterlace { get; set; }
|
|
||||||
|
|
||||||
public bool ReadInputAtNativeFramerate { get; set; }
|
|
||||||
|
|
||||||
public string InputFormat { get; set; }
|
|
||||||
|
|
||||||
public string InputVideoCodec { get; set; }
|
|
||||||
|
|
||||||
public string InputAudioCodec { get; set; }
|
|
||||||
|
|
||||||
public string LiveTvStreamId { get; set; }
|
|
||||||
|
|
||||||
public MediaStream AudioStream { get; set; }
|
|
||||||
public MediaStream VideoStream { get; set; }
|
|
||||||
public MediaStream SubtitleStream { get; set; }
|
|
||||||
public bool HasMediaStreams { get; set; }
|
|
||||||
|
|
||||||
public int SegmentLength = 10;
|
|
||||||
public int HlsListSize;
|
|
||||||
|
|
||||||
public string MimeType { get; set; }
|
|
||||||
public string OrgPn { get; set; }
|
|
||||||
public bool EnableMpegtsM2TsMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the user agent.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The user agent.</value>
|
|
||||||
public string UserAgent { get; set; }
|
|
||||||
|
|
||||||
public EncodingQuality QualitySetting { get; set; }
|
|
||||||
|
|
||||||
public InternalEncodingTask()
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid().ToString("N");
|
|
||||||
CancellationTokenSource = new CancellationTokenSource();
|
|
||||||
StreamFileNames = new List<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableDebugLogging { get; set; }
|
|
||||||
|
|
||||||
internal void OnBegin()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void OnCompleted()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void OnError()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,311 +0,0 @@
|
||||||
using MediaBrowser.Controller.Configuration;
|
|
||||||
using MediaBrowser.Controller.Dlna;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Configuration;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.LiveTv;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
|
||||||
{
|
|
||||||
public class InternalEncodingTaskFactory
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
|
||||||
private readonly IItemRepository _itemRepo;
|
|
||||||
private readonly IServerConfigurationManager _config;
|
|
||||||
|
|
||||||
public InternalEncodingTaskFactory(ILibraryManager libraryManager, ILiveTvManager liveTvManager, IItemRepository itemRepo, IServerConfigurationManager config)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
_liveTvManager = liveTvManager;
|
|
||||||
_itemRepo = itemRepo;
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<InternalEncodingTask> Create(EncodingOptions request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
ValidateInput(request);
|
|
||||||
|
|
||||||
var state = new InternalEncodingTask
|
|
||||||
{
|
|
||||||
Request = request
|
|
||||||
};
|
|
||||||
|
|
||||||
var item = string.IsNullOrEmpty(request.MediaSourceId) ?
|
|
||||||
_libraryManager.GetItemById(new Guid(request.ItemId)) :
|
|
||||||
_libraryManager.GetItemById(new Guid(request.MediaSourceId));
|
|
||||||
|
|
||||||
if (item is ILiveTvRecording)
|
|
||||||
{
|
|
||||||
var recording = await _liveTvManager.GetInternalRecording(request.ItemId, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
state.InputVideoType = VideoType.VideoFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = recording.RecordingInfo.Path;
|
|
||||||
var mediaUrl = recording.RecordingInfo.Url;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(path) && string.IsNullOrWhiteSpace(mediaUrl))
|
|
||||||
{
|
|
||||||
var streamInfo = await _liveTvManager.GetRecordingStream(request.ItemId, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
state.LiveTvStreamId = streamInfo.Id;
|
|
||||||
|
|
||||||
path = streamInfo.Path;
|
|
||||||
mediaUrl = streamInfo.Url;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(path) && File.Exists(path))
|
|
||||||
{
|
|
||||||
state.MediaPath = path;
|
|
||||||
state.IsInputRemote = false;
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(mediaUrl))
|
|
||||||
{
|
|
||||||
state.MediaPath = mediaUrl;
|
|
||||||
state.IsInputRemote = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.InputRunTimeTicks = recording.RunTimeTicks;
|
|
||||||
if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsInputRemote)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress;
|
|
||||||
state.AudioSync = "1000";
|
|
||||||
state.DeInterlace = true;
|
|
||||||
state.InputVideoSync = "-1";
|
|
||||||
state.InputAudioSync = "1";
|
|
||||||
}
|
|
||||||
else if (item is LiveTvChannel)
|
|
||||||
{
|
|
||||||
var channel = _liveTvManager.GetInternalChannel(request.ItemId);
|
|
||||||
|
|
||||||
if (string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
state.InputVideoType = VideoType.VideoFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
var streamInfo = await _liveTvManager.GetChannelStream(request.ItemId, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
state.LiveTvStreamId = streamInfo.Id;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(streamInfo.Path) && File.Exists(streamInfo.Path))
|
|
||||||
{
|
|
||||||
state.MediaPath = streamInfo.Path;
|
|
||||||
state.IsInputRemote = false;
|
|
||||||
|
|
||||||
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(streamInfo.Url))
|
|
||||||
{
|
|
||||||
state.MediaPath = streamInfo.Url;
|
|
||||||
state.IsInputRemote = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.ReadInputAtNativeFramerate = true;
|
|
||||||
state.AudioSync = "1000";
|
|
||||||
state.DeInterlace = true;
|
|
||||||
state.InputVideoSync = "-1";
|
|
||||||
state.InputAudioSync = "1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.MediaPath = item.Path;
|
|
||||||
state.IsInputRemote = item.LocationType == LocationType.Remote;
|
|
||||||
|
|
||||||
var video = item as Video;
|
|
||||||
|
|
||||||
if (video != null)
|
|
||||||
{
|
|
||||||
state.InputVideoType = video.VideoType;
|
|
||||||
state.IsoType = video.IsoType;
|
|
||||||
|
|
||||||
state.StreamFileNames = video.PlayableStreamFileNames.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
state.InputRunTimeTicks = item.RunTimeTicks;
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoRequest = request as VideoEncodingOptions;
|
|
||||||
|
|
||||||
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id
|
|
||||||
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
if (videoRequest != null)
|
|
||||||
{
|
|
||||||
state.VideoStream = GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
|
|
||||||
state.SubtitleStream = GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
|
|
||||||
state.AudioStream = GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
|
|
||||||
|
|
||||||
if (state.VideoStream != null && state.VideoStream.IsInterlaced)
|
|
||||||
{
|
|
||||||
state.DeInterlace = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.HasMediaStreams = mediaStreams.Count > 0;
|
|
||||||
|
|
||||||
state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
|
|
||||||
state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
|
|
||||||
|
|
||||||
state.QualitySetting = GetQualitySetting();
|
|
||||||
|
|
||||||
ApplyDeviceProfileSettings(state);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateInput(EncodingOptions request)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(request.ItemId))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("ItemId is required.");
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(request.OutputPath))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("OutputPath is required.");
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(request.Container))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Container is required.");
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(request.AudioCodec))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("AudioCodec is required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoRequest = request as VideoEncodingOptions;
|
|
||||||
|
|
||||||
if (videoRequest == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines which stream will be used for playback
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="allStream">All stream.</param>
|
|
||||||
/// <param name="desiredIndex">Index of the desired.</param>
|
|
||||||
/// <param name="type">The type.</param>
|
|
||||||
/// <param name="returnFirstIfNoIndex">if set to <c>true</c> [return first if no index].</param>
|
|
||||||
/// <returns>MediaStream.</returns>
|
|
||||||
private MediaStream GetMediaStream(IEnumerable<MediaStream> allStream, int? desiredIndex, MediaStreamType type, bool returnFirstIfNoIndex = true)
|
|
||||||
{
|
|
||||||
var streams = allStream.Where(s => s.Type == type).OrderBy(i => i.Index).ToList();
|
|
||||||
|
|
||||||
if (desiredIndex.HasValue)
|
|
||||||
{
|
|
||||||
var stream = streams.FirstOrDefault(s => s.Index == desiredIndex.Value);
|
|
||||||
|
|
||||||
if (stream != null)
|
|
||||||
{
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnFirstIfNoIndex && type == MediaStreamType.Audio)
|
|
||||||
{
|
|
||||||
return streams.FirstOrDefault(i => i.Channels.HasValue && i.Channels.Value > 0) ??
|
|
||||||
streams.FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just return the first one
|
|
||||||
return returnFirstIfNoIndex ? streams.FirstOrDefault() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyDeviceProfileSettings(InternalEncodingTask state)
|
|
||||||
{
|
|
||||||
var profile = state.Request.DeviceProfile;
|
|
||||||
|
|
||||||
if (profile == null)
|
|
||||||
{
|
|
||||||
// Don't use settings from the default profile.
|
|
||||||
// Only use a specific profile if it was requested.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var container = state.Request.Container;
|
|
||||||
|
|
||||||
var audioCodec = state.Request.AudioCodec;
|
|
||||||
|
|
||||||
if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
|
|
||||||
{
|
|
||||||
audioCodec = state.AudioStream.Codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
|
|
||||||
|
|
||||||
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
|
|
||||||
{
|
|
||||||
videoCodec = state.VideoStream.Codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
//var mediaProfile = state.VideoRequest == null ?
|
|
||||||
// profile.GetAudioMediaProfile(container, audioCodec) :
|
|
||||||
// profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
|
|
||||||
|
|
||||||
//if (mediaProfile != null)
|
|
||||||
//{
|
|
||||||
// state.MimeType = mediaProfile.MimeType;
|
|
||||||
// state.OrgPn = mediaProfile.OrgPn;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var transcodingProfile = state.VideoRequest == null ?
|
|
||||||
// profile.GetAudioTranscodingProfile(container, audioCodec) :
|
|
||||||
// profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec);
|
|
||||||
|
|
||||||
//if (transcodingProfile != null)
|
|
||||||
//{
|
|
||||||
// //state.EstimateContentLength = transcodingProfile.EstimateContentLength;
|
|
||||||
// state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
|
|
||||||
// //state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
|
|
||||||
|
|
||||||
// if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.VideoProfile))
|
|
||||||
// {
|
|
||||||
// state.VideoRequest.VideoProfile = transcodingProfile.VideoProfile;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
private EncodingQuality GetQualitySetting()
|
|
||||||
{
|
|
||||||
var quality = _config.Configuration.MediaEncodingQuality;
|
|
||||||
|
|
||||||
if (quality == EncodingQuality.Auto)
|
|
||||||
{
|
|
||||||
var cpuCount = Environment.ProcessorCount;
|
|
||||||
|
|
||||||
if (cpuCount >= 4)
|
|
||||||
{
|
|
||||||
//return EncodingQuality.HighQuality;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EncodingQuality.HighSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return quality;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -853,7 +853,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
|
public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new ImageEncoder(FFMpegPath, _logger, _fileSystem, _appPaths).EncodeImage(options, cancellationToken);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -53,12 +53,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="BdInfo\BdInfoExaminer.cs" />
|
<Compile Include="BdInfo\BdInfoExaminer.cs" />
|
||||||
<Compile Include="Encoder\AudioEncoder.cs" />
|
|
||||||
<Compile Include="Encoder\EncodingUtils.cs" />
|
<Compile Include="Encoder\EncodingUtils.cs" />
|
||||||
<Compile Include="Encoder\FFMpegProcess.cs" />
|
|
||||||
<Compile Include="Encoder\ImageEncoder.cs" />
|
|
||||||
<Compile Include="Encoder\InternalEncodingTask.cs" />
|
|
||||||
<Compile Include="Encoder\InternalEncodingTaskFactory.cs" />
|
|
||||||
<Compile Include="Encoder\MediaEncoder.cs" />
|
<Compile Include="Encoder\MediaEncoder.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Subtitles\ISubtitleParser.cs" />
|
<Compile Include="Subtitles\ISubtitleParser.cs" />
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace MediaBrowser.Model.Session
|
||||||
|
|
||||||
public bool SupportsMediaControl { get; set; }
|
public bool SupportsMediaControl { get; set; }
|
||||||
|
|
||||||
|
public string MessageCallbackUrl { get; set; }
|
||||||
|
|
||||||
public SessionCapabilities()
|
public SessionCapabilities()
|
||||||
{
|
{
|
||||||
PlayableMediaTypes = new List<string>();
|
PlayableMediaTypes = new List<string>();
|
||||||
|
|
|
@ -156,6 +156,23 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaSources(string id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var item = (IChannelMediaItem)_libraryManager.GetItemById(id);
|
||||||
|
|
||||||
|
var channelGuid = new Guid(item.ChannelId);
|
||||||
|
var channel = _channelEntities.First(i => i.Id == channelGuid);
|
||||||
|
|
||||||
|
var requiresCallback = channel as IRequiresMediaInfoCallback;
|
||||||
|
|
||||||
|
if (requiresCallback != null)
|
||||||
|
{
|
||||||
|
return requiresCallback.GetChannelItemMediaInfo(item.ExternalId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<IEnumerable<ChannelMediaInfo>>(item.ChannelMediaSources);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken)
|
private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name));
|
var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name));
|
||||||
|
@ -303,10 +320,16 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
|
|
||||||
var query = new InternalChannelItemQuery
|
var query = new InternalChannelItemQuery
|
||||||
{
|
{
|
||||||
User = user,
|
User = user
|
||||||
CategoryId = categoryId
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(categoryId))
|
||||||
|
{
|
||||||
|
var categoryItem = (IChannelItem)_libraryManager.GetItemById(new Guid(categoryId));
|
||||||
|
|
||||||
|
query.CategoryId = categoryItem.ExternalId;
|
||||||
|
}
|
||||||
|
|
||||||
var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
|
var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
CacheResponse(result, cachePath);
|
CacheResponse(result, cachePath);
|
||||||
|
@ -380,7 +403,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
private string GetIdToHash(string externalId)
|
private string GetIdToHash(string externalId)
|
||||||
{
|
{
|
||||||
// Increment this as needed to force new downloads
|
// Increment this as needed to force new downloads
|
||||||
return externalId + "4";
|
return externalId + "7";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<BaseItem> GetChannelItemEntity(ChannelItemInfo info, string internalChannnelId, CancellationToken cancellationToken)
|
private async Task<BaseItem> GetChannelItemEntity(ChannelItemInfo info, string internalChannnelId, CancellationToken cancellationToken)
|
||||||
|
@ -434,10 +457,6 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
item.Id = id;
|
item.Id = id;
|
||||||
item.RunTimeTicks = info.RunTimeTicks;
|
item.RunTimeTicks = info.RunTimeTicks;
|
||||||
|
|
||||||
var mediaSource = info.MediaSources.FirstOrDefault();
|
|
||||||
|
|
||||||
item.Path = mediaSource == null ? null : mediaSource.Path;
|
|
||||||
|
|
||||||
if (isNew)
|
if (isNew)
|
||||||
{
|
{
|
||||||
item.Name = info.Name;
|
item.Name = info.Name;
|
||||||
|
@ -464,12 +483,22 @@ namespace MediaBrowser.Server.Implementations.Channels
|
||||||
channelItem.ChannelId = internalChannnelId;
|
channelItem.ChannelId = internalChannnelId;
|
||||||
channelItem.ChannelItemType = info.Type;
|
channelItem.ChannelItemType = info.Type;
|
||||||
|
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
channelItem.Tags = info.Tags;
|
||||||
|
}
|
||||||
|
|
||||||
var channelMediaItem = item as IChannelMediaItem;
|
var channelMediaItem = item as IChannelMediaItem;
|
||||||
|
|
||||||
if (channelMediaItem != null)
|
if (channelMediaItem != null)
|
||||||
{
|
{
|
||||||
channelMediaItem.IsInfiniteStream = info.IsInfiniteStream;
|
channelMediaItem.IsInfiniteStream = info.IsInfiniteStream;
|
||||||
channelMediaItem.ContentType = info.ContentType;
|
channelMediaItem.ContentType = info.ContentType;
|
||||||
|
channelMediaItem.ChannelMediaSources = info.MediaSources;
|
||||||
|
|
||||||
|
var mediaSource = info.MediaSources.FirstOrDefault();
|
||||||
|
|
||||||
|
item.Path = mediaSource == null ? null : mediaSource.Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNew)
|
if (isNew)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using MediaBrowser.Common.Net;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Controller;
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
|
@ -16,23 +19,18 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
{
|
{
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
private readonly IServerApplicationHost _appHost;
|
|
||||||
|
|
||||||
public SessionInfo Session { get; private set; }
|
public SessionInfo Session { get; private set; }
|
||||||
|
|
||||||
//var postUrl = string.Format("http://{0}/mediabrowser/message", session.RemoteEndPoint);
|
|
||||||
|
|
||||||
private readonly string _postUrl;
|
private readonly string _postUrl;
|
||||||
|
|
||||||
public HttpSessionController(IHttpClient httpClient,
|
public HttpSessionController(IHttpClient httpClient,
|
||||||
IJsonSerializer json,
|
IJsonSerializer json,
|
||||||
IServerApplicationHost appHost,
|
|
||||||
SessionInfo session,
|
SessionInfo session,
|
||||||
string postUrl)
|
string postUrl)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_json = json;
|
_json = json;
|
||||||
_appHost = appHost;
|
|
||||||
Session = session;
|
Session = session;
|
||||||
_postUrl = postUrl;
|
_postUrl = postUrl;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +61,21 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task SendMessage(string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return SendMessage(name, new NameValueCollection(), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SendMessage(string name, NameValueCollection args, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return SendMessage(new WebSocketMessage<string>
|
||||||
|
{
|
||||||
|
MessageType = name,
|
||||||
|
Data = string.Empty
|
||||||
|
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
|
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
|
@ -80,22 +93,25 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
|
|
||||||
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
|
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessage(new WebSocketMessage<PlayRequest>
|
return Task.FromResult(true);
|
||||||
{
|
//return SendMessage(new WebSocketMessage<PlayRequest>
|
||||||
MessageType = "Play",
|
//{
|
||||||
Data = command
|
// MessageType = "Play",
|
||||||
|
// Data = command
|
||||||
|
|
||||||
}, cancellationToken);
|
//}, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
|
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessage(new WebSocketMessage<PlaystateRequest>
|
var args = new Dictionary<string, string>();
|
||||||
{
|
|
||||||
MessageType = "Playstate",
|
|
||||||
Data = command
|
|
||||||
|
|
||||||
}, cancellationToken);
|
if (command.Command == PlaystateCommand.Seek)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendMessage(command.Command.ToString(), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
|
public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
|
||||||
|
@ -103,14 +119,9 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessage(new WebSocketMessage<SystemInfo>
|
return SendMessage("RestartRequired", cancellationToken);
|
||||||
{
|
|
||||||
MessageType = "RestartRequired",
|
|
||||||
Data = _appHost.GetSystemInfo()
|
|
||||||
|
|
||||||
}, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
|
public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
|
||||||
|
@ -120,22 +131,12 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
|
|
||||||
public Task SendServerShutdownNotification(CancellationToken cancellationToken)
|
public Task SendServerShutdownNotification(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessage(new WebSocketMessage<string>
|
return SendMessage("ServerShuttingDown", cancellationToken);
|
||||||
{
|
|
||||||
MessageType = "ServerShuttingDown",
|
|
||||||
Data = string.Empty
|
|
||||||
|
|
||||||
}, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendServerRestartNotification(CancellationToken cancellationToken)
|
public Task SendServerRestartNotification(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessage(new WebSocketMessage<string>
|
return SendMessage("ServerRestarting", cancellationToken);
|
||||||
{
|
|
||||||
MessageType = "ServerRestarting",
|
|
||||||
Data = string.Empty
|
|
||||||
|
|
||||||
}, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
||||||
|
@ -147,5 +148,13 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
|
|
||||||
}, cancellationToken);
|
}, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ToQueryString(Dictionary<string, string> nvc)
|
||||||
|
{
|
||||||
|
var array = (from item in nvc
|
||||||
|
select string.Format("{0}={1}", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)))
|
||||||
|
.ToArray();
|
||||||
|
return "?" + string.Join("&", array);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Globalization;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Events;
|
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
|
@ -14,10 +15,12 @@ using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Library;
|
using MediaBrowser.Model.Library;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using MediaBrowser.Model.Session;
|
using MediaBrowser.Model.Session;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -51,6 +54,10 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
private readonly IItemRepository _itemRepo;
|
private readonly IItemRepository _itemRepo;
|
||||||
|
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
private readonly IServerApplicationHost _appHost;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the configuration manager.
|
/// Gets or sets the configuration manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -93,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="userRepository">The user repository.</param>
|
/// <param name="userRepository">The user repository.</param>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo)
|
public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient)
|
||||||
{
|
{
|
||||||
_userDataRepository = userDataRepository;
|
_userDataRepository = userDataRepository;
|
||||||
_configurationManager = configurationManager;
|
_configurationManager = configurationManager;
|
||||||
|
@ -105,6 +112,9 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_itemRepo = itemRepo;
|
_itemRepo = itemRepo;
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
_appHost = appHost;
|
||||||
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -908,11 +918,13 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
{
|
{
|
||||||
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
|
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
|
||||||
|
|
||||||
|
var info = _appHost.GetSystemInfo();
|
||||||
|
|
||||||
var tasks = sessions.Select(session => Task.Run(async () =>
|
var tasks = sessions.Select(session => Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await session.SessionController.SendRestartRequiredNotification(cancellationToken).ConfigureAwait(false);
|
await session.SessionController.SendRestartRequiredNotification(info, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1135,6 +1147,18 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
|
session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
|
||||||
session.SupportedCommands = capabilities.SupportedCommands;
|
session.SupportedCommands = capabilities.SupportedCommands;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(capabilities.MessageCallbackUrl))
|
||||||
|
{
|
||||||
|
var postUrl = string.Format("http://{0}{1}", session.RemoteEndPoint, capabilities.MessageCallbackUrl);
|
||||||
|
|
||||||
|
var controller = session.SessionController as HttpSessionController;
|
||||||
|
|
||||||
|
if (controller == null)
|
||||||
|
{
|
||||||
|
session.SessionController = new HttpSessionController(_httpClient, _jsonSerializer, session, postUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EventHelper.FireEventIfNotNull(CapabilitiesChanged, this, new SessionEventArgs
|
EventHelper.FireEventIfNotNull(CapabilitiesChanged, this, new SessionEventArgs
|
||||||
{
|
{
|
||||||
SessionInfo = session
|
SessionInfo = session
|
||||||
|
|
|
@ -35,19 +35,17 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
/// The _dto service
|
/// The _dto service
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IJsonSerializer _json;
|
private readonly IJsonSerializer _json;
|
||||||
private readonly IServerApplicationHost _appHost;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
|
/// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sessionManager">The session manager.</param>
|
/// <param name="sessionManager">The session manager.</param>
|
||||||
/// <param name="logManager">The log manager.</param>
|
/// <param name="logManager">The log manager.</param>
|
||||||
/// <param name="appHost">The application host.</param>
|
/// <param name="json">The json.</param>
|
||||||
public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IServerApplicationHost appHost, IJsonSerializer json)
|
public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json)
|
||||||
{
|
{
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
_logger = logManager.GetLogger(GetType().Name);
|
||||||
_appHost = appHost;
|
|
||||||
_json = json;
|
_json = json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
|
|
||||||
if (controller == null)
|
if (controller == null)
|
||||||
{
|
{
|
||||||
controller = new WebSocketController(session, _appHost, _logger, _sessionManager);
|
controller = new WebSocketController(session, _logger, _sessionManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.AddWebSocket(message.Connection);
|
controller.AddWebSocket(message.Connection);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -19,15 +18,13 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
public SessionInfo Session { get; private set; }
|
public SessionInfo Session { get; private set; }
|
||||||
public IReadOnlyList<IWebSocketConnection> Sockets { get; private set; }
|
public IReadOnlyList<IWebSocketConnection> Sockets { get; private set; }
|
||||||
|
|
||||||
private readonly IServerApplicationHost _appHost;
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
private readonly ISessionManager _sessionManager;
|
private readonly ISessionManager _sessionManager;
|
||||||
|
|
||||||
public WebSocketController(SessionInfo session, IServerApplicationHost appHost, ILogger logger, ISessionManager sessionManager)
|
public WebSocketController(SessionInfo session, ILogger logger, ISessionManager sessionManager)
|
||||||
{
|
{
|
||||||
Session = session;
|
Session = session;
|
||||||
_appHost = appHost;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sessionManager = sessionManager;
|
_sessionManager = sessionManager;
|
||||||
Sockets = new List<IWebSocketConnection>();
|
Sockets = new List<IWebSocketConnection>();
|
||||||
|
@ -121,14 +118,15 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the restart required message.
|
/// Sends the restart required message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="info">The information.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return SendMessages(new WebSocketMessage<SystemInfo>
|
return SendMessages(new WebSocketMessage<SystemInfo>
|
||||||
{
|
{
|
||||||
MessageType = "RestartRequired",
|
MessageType = "RestartRequired",
|
||||||
Data = _appHost.GetSystemInfo()
|
Data = info
|
||||||
|
|
||||||
}, cancellationToken);
|
}, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
|
@ -496,7 +496,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager);
|
DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager);
|
||||||
RegisterSingleInstance(DtoService);
|
RegisterSingleInstance(DtoService);
|
||||||
|
|
||||||
SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository);
|
SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient);
|
||||||
RegisterSingleInstance(SessionManager);
|
RegisterSingleInstance(SessionManager);
|
||||||
|
|
||||||
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
|
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.367</version>
|
<version>3.0.369</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.367" />
|
<dependency id="MediaBrowser.Common" version="3.0.369" />
|
||||||
<dependency id="NLog" version="2.1.0" />
|
<dependency id="NLog" version="2.1.0" />
|
||||||
<dependency id="SimpleInjector" version="2.5.0" />
|
<dependency id="SimpleInjector" version="2.5.0" />
|
||||||
<dependency id="sharpcompress" version="0.10.2" />
|
<dependency id="sharpcompress" version="0.10.2" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.367</version>
|
<version>3.0.369</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.367</version>
|
<version>3.0.369</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.367" />
|
<dependency id="MediaBrowser.Common" version="3.0.369" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user