channel fixes

This commit is contained in:
Luke Pulverenti 2014-05-18 15:58:42 -04:00
parent ca5989cb17
commit 3ccecd3ca3
39 changed files with 287 additions and 1121 deletions

View File

@ -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;

View File

@ -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)
{ {
} }

View File

@ -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)
{ {
} }

View File

@ -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)
{ {
} }

View File

@ -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)
{ {
} }

View File

@ -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>

View File

@ -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;
} }

View File

@ -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;

View File

@ -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
}); });
} }

View File

@ -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;
}
}
} }
} }

View File

@ -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>();
}
} }
} }

View File

@ -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);
} }
} }

View File

@ -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;
} }
} }
} }

View File

@ -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;
}
}
} }
} }

View File

@ -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);
}
} }

View File

@ -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; }

View File

@ -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);
} }
} }

View File

@ -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; }
} }
} }

View File

@ -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>

View File

@ -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.

View File

@ -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);
} }

View File

@ -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());
}
}
}

View File

@ -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.");
}
}
} }
} }

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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()
{
}
}
}

View File

@ -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;
}
}
}

View File

@ -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>

View File

@ -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" />

View File

@ -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>();

View File

@ -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)

View File

@ -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);
}
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);

View File

@ -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" />

View File

@ -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>

View File

@ -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>