commit
b2cbe8b4e1
|
@ -648,10 +648,8 @@ namespace MediaBrowser.Api.Images
|
|||
|
||||
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
||||
|
||||
var clientFormats = GetClientSupportedFormats();
|
||||
|
||||
if (serverFormats.Contains(ImageFormat.Webp) &&
|
||||
clientFormats.Contains(ImageFormat.Webp))
|
||||
GetClientSupportedFormats().Contains(ImageFormat.Webp))
|
||||
{
|
||||
return ImageFormat.Webp;
|
||||
}
|
||||
|
|
|
@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var originalItem = item;
|
||||
|
||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
}
|
||||
|
||||
var themeSongIds = GetThemeSongIds(item);
|
||||
|
||||
if (themeSongIds.Count == 0 && request.InheritFromParent)
|
||||
{
|
||||
var album = originalItem as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
var linkedItemWithThemes = album.SoundtrackIds
|
||||
.Select(i => _libraryManager.GetItemById(i))
|
||||
.FirstOrDefault(i => GetThemeSongIds(i).Count > 0);
|
||||
|
||||
if (linkedItemWithThemes != null)
|
||||
{
|
||||
themeSongIds = GetThemeSongIds(linkedItemWithThemes);
|
||||
item = linkedItemWithThemes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
||||
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
|
@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var originalItem = item;
|
||||
|
||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
{
|
||||
item = item.Parent;
|
||||
}
|
||||
|
||||
var themeVideoIds = GetThemeVideoIds(item);
|
||||
|
||||
if (themeVideoIds.Count == 0 && request.InheritFromParent)
|
||||
{
|
||||
var album = originalItem as MusicAlbum;
|
||||
|
||||
if (album == null)
|
||||
{
|
||||
album = originalItem.Parents.OfType<MusicAlbum>().FirstOrDefault();
|
||||
}
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
var linkedItemWithThemes = album.SoundtrackIds
|
||||
.Select(i => _libraryManager.GetItemById(i))
|
||||
.FirstOrDefault(i => GetThemeVideoIds(i).Count > 0);
|
||||
|
||||
if (linkedItemWithThemes != null)
|
||||
{
|
||||
themeVideoIds = GetThemeVideoIds(linkedItemWithThemes);
|
||||
item = linkedItemWithThemes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dtoOptions = GetDtoOptions(request);
|
||||
|
||||
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
||||
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
|
@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
|
|||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||
protected IZipClient ZipClient { get; private set; }
|
||||
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||
/// </summary>
|
||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
|
||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer)
|
||||
{
|
||||
JsonSerializer = jsonSerializer;
|
||||
ZipClient = zipClient;
|
||||
MediaSourceManager = mediaSourceManager;
|
||||
DeviceManager = deviceManager;
|
||||
|
@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
|
|||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
|
||||
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
|
||||
}
|
||||
|
||||
// If a fixed width was requested
|
||||
|
@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// If a max width was requested
|
||||
else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
||||
else if (request.MaxWidth.HasValue)
|
||||
{
|
||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||
|
||||
|
@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// If a max height was requested
|
||||
else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
||||
else if (request.MaxHeight.HasValue)
|
||||
{
|
||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
||||
}
|
||||
|
||||
else if (request.MaxWidth.HasValue ||
|
||||
request.MaxHeight.HasValue ||
|
||||
request.Width.HasValue ||
|
||||
request.Height.HasValue)
|
||||
{
|
||||
if (state.VideoStream != null)
|
||||
{
|
||||
// Need to perform calculations manually
|
||||
|
||||
// Try to account for bad media info
|
||||
var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
|
||||
var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
|
||||
|
||||
var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
||||
|
||||
var manualWidthParam = outputSize.Width.ToString(UsCulture);
|
||||
var manualHeightParam = outputSize.Height.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
|
||||
}
|
||||
}
|
||||
|
||||
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filters[filters.Count - 1] += ":flags=fast_bilinear";
|
||||
|
@ -1027,7 +1008,7 @@ namespace MediaBrowser.Api.Playback
|
|||
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
|
||||
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
|
||||
|
||||
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
|
||||
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
|
||||
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
||||
|
@ -1105,6 +1086,10 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error reading ffmpeg log", ex);
|
||||
|
@ -2033,8 +2018,6 @@ namespace MediaBrowser.Api.Playback
|
|||
profile.GetVideoMediaProfile(state.OutputContainer,
|
||||
audioCodec,
|
||||
videoCodec,
|
||||
state.OutputAudioBitrate,
|
||||
state.OutputAudioChannels,
|
||||
state.OutputWidth,
|
||||
state.OutputHeight,
|
||||
state.TargetVideoBitDepth,
|
||||
|
@ -2121,8 +2104,6 @@ namespace MediaBrowser.Api.Playback
|
|||
state.OutputHeight,
|
||||
state.TargetVideoBitDepth,
|
||||
state.OutputVideoBitrate,
|
||||
state.OutputAudioBitrate,
|
||||
state.OutputAudioChannels,
|
||||
state.TargetTimestamp,
|
||||
isStaticallyStreamed,
|
||||
state.RunTimeTicks,
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
|||
|
||||
public class MpegDashService : BaseHlsService
|
||||
{
|
||||
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
||||
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||
{
|
||||
NetworkManager = networkManager;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
{
|
||||
|
@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
public abstract class BaseHlsService : BaseStreamingService
|
||||
{
|
||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Model.Dlna;
|
|||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
public class DynamicHlsService : BaseHlsService
|
||||
{
|
||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||
{
|
||||
NetworkManager = networkManager;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
|
||||
|
@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
public class VideoHlsService : BaseHlsService
|
||||
{
|
||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -18,16 +18,6 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
[Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")]
|
||||
public class GetLiveMediaInfo : IReturn<PlaybackInfoResponse>
|
||||
{
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
|
||||
public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
|
||||
{
|
||||
|
@ -55,6 +45,19 @@ namespace MediaBrowser.Api.Playback
|
|||
public string LiveStreamId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Playback/BitrateTest", "GET")]
|
||||
public class GetBitrateTestBytes : IReturn<PlaybackInfoResponse>
|
||||
{
|
||||
[ApiMember(Name = "Size", Description = "Size", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public long Size { get; set; }
|
||||
|
||||
public GetBitrateTestBytes()
|
||||
{
|
||||
// 100k
|
||||
Size = 102400;
|
||||
}
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class MediaInfoService : BaseApiService
|
||||
{
|
||||
|
@ -73,13 +76,19 @@ namespace MediaBrowser.Api.Playback
|
|||
_networkManager = networkManager;
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetPlaybackInfo request)
|
||||
public object Get(GetBitrateTestBytes request)
|
||||
{
|
||||
var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
|
||||
return ToOptimizedResult(result);
|
||||
var bytes = new byte[request.Size];
|
||||
|
||||
for (var i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
bytes[i] = 0;
|
||||
}
|
||||
|
||||
return ResultFactory.GetResult(bytes, "application/octet-stream");
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetLiveMediaInfo request)
|
||||
public async Task<object> Get(GetPlaybackInfo request)
|
||||
{
|
||||
var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
|
||||
return ToOptimizedResult(result);
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
public class AudioService : BaseProgressiveStreamingService
|
||||
{
|
||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
|
|||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
protected readonly IImageProcessor ImageProcessor;
|
||||
protected readonly IHttpClient HttpClient;
|
||||
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||
{
|
||||
ImageProcessor = imageProcessor;
|
||||
HttpClient = httpClient;
|
||||
|
|
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
public class VideoService : BaseProgressiveStreamingService
|
||||
{
|
||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Subtitles
|
|||
}
|
||||
|
||||
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
|
||||
[Authenticated]
|
||||
public class GetSubtitlePlaylist
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -48,9 +48,9 @@
|
|||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="NLog, Version=3.2.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<Reference Include="NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\NLog.3.2.0.0\lib\net45\NLog.dll</HintPath>
|
||||
<HintPath>..\packages\NLog.3.2.1\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
@ -58,11 +58,8 @@
|
|||
</Reference>
|
||||
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimpleInjector.Diagnostics, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
|
||||
<HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
|
|
@ -6,16 +6,29 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Common.Implementations.Networking
|
||||
{
|
||||
public abstract class BaseNetworkManager
|
||||
{
|
||||
protected ILogger Logger { get; private set; }
|
||||
private Timer _clearCacheTimer;
|
||||
|
||||
protected BaseNetworkManager(ILogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
// Can't use network change events due to a crash in Linux
|
||||
_clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
private void ClearCacheTimerCallback(object state)
|
||||
{
|
||||
lock (_localIpAddressSyncLock)
|
||||
{
|
||||
_localIpAddresses = null;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile List<string> _localIpAddresses;
|
||||
|
@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
var addresses = GetLocalIpAddressesInternal().ToList();
|
||||
|
||||
_localIpAddresses = addresses;
|
||||
BindEvents();
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
return _localIpAddresses;
|
||||
}
|
||||
|
||||
private void BindEvents()
|
||||
{
|
||||
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
|
||||
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
|
||||
|
||||
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
||||
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
||||
}
|
||||
|
||||
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||
{
|
||||
Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
|
||||
|
||||
lock (_localIpAddressSyncLock)
|
||||
{
|
||||
_localIpAddresses = null;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
|
||||
|
||||
lock (_localIpAddressSyncLock)
|
||||
{
|
||||
_localIpAddresses = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetLocalIpAddressesInternal()
|
||||
{
|
||||
var list = GetIPsDefault()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="3.2.0.0" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
|
||||
<package id="NLog" version="3.2.1" targetFramework="net45" />
|
||||
<package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
|
||||
</packages>
|
||||
|
|
9
MediaBrowser.Controller/Dlna/ISsdpHandler.cs
Normal file
9
MediaBrowser.Controller/Dlna/ISsdpHandler.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface ISsdpHandler
|
||||
{
|
||||
event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace MediaBrowser.Dlna.Ssdp
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public class SsdpMessageEventArgs
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
public Dictionary<string, string> Headers { get; set; }
|
||||
|
||||
public IPAddress LocalIp { get; set; }
|
||||
public byte[] Message { get; set; }
|
||||
|
||||
public SsdpMessageEventArgs()
|
||||
{
|
|
@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
||||
public bool HasEmbeddedImage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override this to true if class should be grouped under a container in indicies
|
||||
/// The container class should be defined via IndexContainer
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool GroupInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to return the folder that should be used to construct a container
|
||||
/// for this item in an index. GroupInIndex should be true as well.
|
||||
/// </summary>
|
||||
/// <value>The index container.</value>
|
||||
[IgnoreDataMember]
|
||||
public override Folder IndexContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return LatestItemsIndexContainer ?? new MusicAlbum { Name = "Unknown Album" };
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsOwnedItems
|
||||
{
|
||||
|
@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
get
|
||||
{
|
||||
return Parents.OfType<MusicAlbum>().FirstOrDefault();
|
||||
return AlbumEntity;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public MusicAlbum AlbumEntity
|
||||
{
|
||||
get { return FindParent<MusicAlbum>(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
|
@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var parent = FindParent<MusicAlbum>();
|
||||
var parent = AlbumEntity;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
||||
{
|
||||
public List<Guid> SoundtrackIds { get; set; }
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
SoundtrackIds = new List<Guid>();
|
||||
Artists = new List<string>();
|
||||
AlbumArtists = new List<string>();
|
||||
}
|
||||
|
@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return Tracks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Songs will group into us so don't also include us in the index
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IncludeInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to true if class should be grouped under a container in indicies
|
||||
/// The container class should be defined via IndexContainer
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool GroupInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unknwon artist
|
||||
/// </summary>
|
||||
private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "<Unknown>" };
|
||||
|
||||
/// <summary>
|
||||
/// Override this to return the folder that should be used to construct a container
|
||||
/// for this item in an index. GroupInIndex should be true as well.
|
||||
/// </summary>
|
||||
/// <value>The index container.</value>
|
||||
[IgnoreDataMember]
|
||||
public override Folder IndexContainer
|
||||
{
|
||||
get { return Parent as MusicArtist ?? UnknwonArtist; }
|
||||
}
|
||||
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The provider ids.</value>
|
||||
public Dictionary<string, string> ProviderIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override this to false if class should be ignored for indexing purposes
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public virtual bool IncludeInIndex
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to true if class should be grouped under a container in indicies
|
||||
/// The container class should be defined via IndexContainer
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public virtual bool GroupInIndex
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to return the folder that should be used to construct a container
|
||||
/// for this item in an index. GroupInIndex should be true as well.
|
||||
/// </summary>
|
||||
/// <value>The index container.</value>
|
||||
[IgnoreDataMember]
|
||||
public virtual Folder IndexContainer
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public virtual Folder LatestItemsIndexContainer
|
||||
{
|
||||
|
|
|
@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// <value>The index number.</value>
|
||||
public int? IndexNumberEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// We want to group into series not show individually in an index
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool GroupInIndex
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
protected override bool SupportsOwnedItems
|
||||
{
|
||||
|
@ -91,19 +81,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We roll up into series
|
||||
/// </summary>
|
||||
/// <value>The index container.</value>
|
||||
[IgnoreDataMember]
|
||||
public override Folder IndexContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return Season;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override Folder LatestItemsIndexContainer
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// </summary>
|
||||
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Seasons are just containers
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IncludeInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
|
@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
get { return Series ?? Parent; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We want to group into our Series
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool GroupInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to return the folder that should be used to construct a container
|
||||
/// for this item in an index. GroupInIndex should be true as well.
|
||||
/// </summary>
|
||||
/// <value>The index container.</value>
|
||||
[IgnoreDataMember]
|
||||
public override Folder IndexContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return Series;
|
||||
}
|
||||
}
|
||||
|
||||
// Genre, Rating and Stuido will all be the same
|
||||
protected override IEnumerable<string> GetIndexByOptions()
|
||||
{
|
||||
|
|
|
@ -94,19 +94,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Series aren't included directly in indices - Their Episodes will roll up to them
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
||||
[IgnoreDataMember]
|
||||
public override bool IncludeInIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
|
|
@ -283,5 +283,17 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
return hour >= schedule.StartHour && hour <= schedule.EndHour;
|
||||
}
|
||||
|
||||
public bool IsFolderGrouped(Guid id)
|
||||
{
|
||||
var config = Configuration;
|
||||
|
||||
if (config.ExcludeFoldersFromGrouping != null)
|
||||
{
|
||||
return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id);
|
||||
}
|
||||
|
||||
return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1754,12 +1754,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
private IEnumerable<Folder> GetMediaFolders(User user)
|
||||
{
|
||||
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
|
||||
|
||||
return user.RootFolder
|
||||
.GetChildren(user, true, true)
|
||||
.OfType<Folder>()
|
||||
.Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
|
||||
.Where(i => user.IsFolderGrouped(i.Id) && !UserView.IsExcludedFromGrouping(i));
|
||||
}
|
||||
|
||||
private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
|
||||
|
|
|
@ -116,7 +116,9 @@
|
|||
<Compile Include="Dlna\IDlnaManager.cs" />
|
||||
<Compile Include="Dlna\IEventManager.cs" />
|
||||
<Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
|
||||
<Compile Include="Dlna\ISsdpHandler.cs" />
|
||||
<Compile Include="Dlna\IUpnpService.cs" />
|
||||
<Compile Include="Dlna\SsdpMessageEventArgs.cs" />
|
||||
<Compile Include="Drawing\IImageProcessor.cs" />
|
||||
<Compile Include="Drawing\ImageCollageOptions.cs" />
|
||||
<Compile Include="Drawing\ImageProcessingOptions.cs" />
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Dlna.ContentDirectory;
|
||||
using MediaBrowser.Dlna.PlayTo;
|
||||
|
|
|
@ -149,8 +149,6 @@ namespace MediaBrowser.Dlna.Didl
|
|||
targetHeight,
|
||||
streamInfo.TargetVideoBitDepth,
|
||||
streamInfo.TargetVideoBitrate,
|
||||
streamInfo.TargetAudioChannels,
|
||||
streamInfo.TargetAudioBitrate,
|
||||
streamInfo.TargetTimestamp,
|
||||
streamInfo.IsDirectStream,
|
||||
streamInfo.RunTimeTicks,
|
||||
|
@ -276,11 +274,9 @@ namespace MediaBrowser.Dlna.Didl
|
|||
streamInfo.AudioCodec,
|
||||
streamInfo.VideoCodec,
|
||||
streamInfo.TargetAudioBitrate,
|
||||
targetChannels,
|
||||
targetWidth,
|
||||
targetHeight,
|
||||
streamInfo.TargetVideoBitDepth,
|
||||
streamInfo.TargetVideoBitrate,
|
||||
streamInfo.TargetVideoProfile,
|
||||
streamInfo.TargetVideoLevel,
|
||||
streamInfo.TargetFramerate,
|
||||
|
|
|
@ -482,7 +482,7 @@ namespace MediaBrowser.Dlna
|
|||
var profile = GetProfile(headers) ??
|
||||
GetDefaultProfile();
|
||||
|
||||
return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName).GetXml();
|
||||
return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName, serverUuId.GetMD5().ToString("N")).GetXml();
|
||||
}
|
||||
|
||||
public ImageStream GetIcon(string filename)
|
||||
|
@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
|
|||
new DirectTvProfile(),
|
||||
new DishHopperJoeyProfile(),
|
||||
new DefaultProfile(),
|
||||
new PopcornHourProfile()
|
||||
new PopcornHourProfile(),
|
||||
new VlcProfile(),
|
||||
new BubbleUpnpProfile()
|
||||
};
|
||||
|
||||
foreach (var item in list)
|
||||
|
|
|
@ -37,13 +37,26 @@ namespace MediaBrowser.Dlna.Main
|
|||
private readonly ILocalizationManager _localization;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
|
||||
private SsdpHandler _ssdpHandler;
|
||||
private readonly SsdpHandler _ssdpHandler;
|
||||
private DeviceDiscovery _deviceDiscovery;
|
||||
|
||||
private readonly List<string> _registeredServerIds = new List<string>();
|
||||
private bool _dlnaServerStarted;
|
||||
|
||||
public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
|
||||
public DlnaEntryPoint(IServerConfigurationManager config,
|
||||
ILogManager logManager,
|
||||
IServerApplicationHost appHost,
|
||||
INetworkManager network,
|
||||
ISessionManager sessionManager,
|
||||
IHttpClient httpClient,
|
||||
ILibraryManager libraryManager,
|
||||
IUserManager userManager,
|
||||
IDlnaManager dlnaManager,
|
||||
IImageProcessor imageProcessor,
|
||||
IUserDataManager userDataManager,
|
||||
ILocalizationManager localization,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
ISsdpHandler ssdpHandler)
|
||||
{
|
||||
_config = config;
|
||||
_appHost = appHost;
|
||||
|
@ -57,6 +70,7 @@ namespace MediaBrowser.Dlna.Main
|
|||
_userDataManager = userDataManager;
|
||||
_localization = localization;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_ssdpHandler = (SsdpHandler)ssdpHandler;
|
||||
_logger = logManager.GetLogger("Dlna");
|
||||
}
|
||||
|
||||
|
@ -109,8 +123,6 @@ namespace MediaBrowser.Dlna.Main
|
|||
{
|
||||
try
|
||||
{
|
||||
_ssdpHandler = new SsdpHandler(_logger, _config, GenerateServerSignature());
|
||||
|
||||
_ssdpHandler.Start();
|
||||
|
||||
_deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
|
||||
|
@ -123,7 +135,7 @@ namespace MediaBrowser.Dlna.Main
|
|||
}
|
||||
}
|
||||
|
||||
private void DisposeSsdpHandler()
|
||||
private void DisposeDeviceDiscovery()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -133,15 +145,6 @@ namespace MediaBrowser.Dlna.Main
|
|||
{
|
||||
_logger.ErrorException("Error disposing device discovery", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_ssdpHandler.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error disposing ssdp handler", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartDlnaServer()
|
||||
|
@ -184,29 +187,6 @@ namespace MediaBrowser.Dlna.Main
|
|||
}
|
||||
}
|
||||
|
||||
private string GenerateServerSignature()
|
||||
{
|
||||
var os = Environment.OSVersion;
|
||||
var pstring = os.Platform.ToString();
|
||||
switch (os.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
case PlatformID.Win32S:
|
||||
case PlatformID.Win32Windows:
|
||||
pstring = "WIN";
|
||||
break;
|
||||
}
|
||||
|
||||
return String.Format(
|
||||
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
|
||||
pstring,
|
||||
IntPtr.Size * 8,
|
||||
os.Version.Major,
|
||||
os.Version.Minor,
|
||||
_appHost.ApplicationVersion
|
||||
);
|
||||
}
|
||||
|
||||
private readonly object _syncLock = new object();
|
||||
private void StartPlayToManager()
|
||||
{
|
||||
|
@ -260,7 +240,7 @@ namespace MediaBrowser.Dlna.Main
|
|||
{
|
||||
DisposeDlnaServer();
|
||||
DisposePlayToManager();
|
||||
DisposeSsdpHandler();
|
||||
DisposeDeviceDiscovery();
|
||||
}
|
||||
|
||||
public void DisposeDlnaServer()
|
||||
|
|
|
@ -77,10 +77,12 @@
|
|||
<Compile Include="Common\DeviceService.cs" />
|
||||
<Compile Include="Didl\DidlBuilder.cs" />
|
||||
<Compile Include="PlayTo\PlayToController.cs" />
|
||||
<Compile Include="Profiles\BubbleUpnpProfile.cs" />
|
||||
<Compile Include="Profiles\DefaultProfile.cs" />
|
||||
<Compile Include="Profiles\DirectTvProfile.cs" />
|
||||
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
||||
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
||||
<Compile Include="Profiles\VlcProfile.cs" />
|
||||
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
||||
<Compile Include="Ssdp\Extensions.cs" />
|
||||
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
||||
|
@ -135,7 +137,6 @@
|
|||
<Compile Include="Server\Headers.cs" />
|
||||
<Compile Include="Server\UpnpDevice.cs" />
|
||||
<Compile Include="Ssdp\SsdpMessageBuilder.cs" />
|
||||
<Compile Include="Ssdp\SsdpMessageEventArgs.cs" />
|
||||
<Compile Include="Ssdp\SsdpHandler.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -205,6 +206,10 @@
|
|||
<EmbeddedResource Include="Images\people480.jpg" />
|
||||
<EmbeddedResource Include="Images\people480.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
|
||||
<EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
|
@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
}
|
||||
|
||||
var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header)
|
||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
|
@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
if (service == null)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to find service");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
if (service == null)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to find service");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
if (service == null)
|
||||
return null;
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType))
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
throw new InvalidOperationException("Unable to find service");
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
throw new InvalidOperationException("Unable to find service");
|
||||
}
|
||||
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
|
|
@ -509,8 +509,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
streamInfo.TargetHeight,
|
||||
streamInfo.TargetVideoBitDepth,
|
||||
streamInfo.TargetVideoBitrate,
|
||||
streamInfo.TargetAudioChannels,
|
||||
streamInfo.TargetAudioBitrate,
|
||||
streamInfo.TargetTimestamp,
|
||||
streamInfo.IsDirectStream,
|
||||
streamInfo.RunTimeTicks,
|
||||
|
@ -770,8 +768,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
|
||||
|
||||
if (newItem.StreamInfo.IsDirectStream)
|
||||
if (newItem.StreamInfo.IsDirectStream && newPosition > 0)
|
||||
{
|
||||
// This is rather arbitrary, but give the player time to start playing
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
|
||||
await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Dlna.PlayTo
|
||||
{
|
||||
|
@ -34,6 +35,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
private readonly DeviceDiscovery _deviceDiscovery;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
|
||||
private readonly List<string> _nonRendererUrls = new List<string>();
|
||||
private Timer _clearNonRenderersTimer;
|
||||
|
||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
|
||||
{
|
||||
_logger = logger;
|
||||
|
@ -53,9 +57,19 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
public void Start()
|
||||
{
|
||||
_clearNonRenderersTimer = new Timer(OnClearUrlTimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
|
||||
|
||||
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
|
||||
}
|
||||
|
||||
private void OnClearUrlTimerCallback(object state)
|
||||
{
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
_nonRendererUrls.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
|
||||
{
|
||||
var localIp = e.LocalIp;
|
||||
|
@ -68,7 +82,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
string location;
|
||||
if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
|
||||
|
||||
|
||||
// It has to report that it's a media renderer
|
||||
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
|
||||
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
|
@ -85,62 +99,75 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
var uri = new Uri(location);
|
||||
|
||||
// TODO: Cache list of non-renderers by url to avoid repeating calls
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
|
||||
|
||||
if (device.RendererCommands != null)
|
||||
if (device.RendererCommands == null)
|
||||
{
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var controller = sessionInfo.SessionController as PlayToController;
|
||||
|
||||
if (controller == null)
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
var serverAddress = GetServerAddress(localIp);
|
||||
string accessToken = null;
|
||||
|
||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
|
||||
_sessionManager,
|
||||
_libraryManager,
|
||||
_logger,
|
||||
_dlnaManager,
|
||||
_userManager,
|
||||
_imageProcessor,
|
||||
serverAddress,
|
||||
accessToken,
|
||||
_deviceDiscovery,
|
||||
_userDataManager,
|
||||
_localization,
|
||||
_mediaSourceManager);
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
|
||||
_dlnaManager.GetDefaultProfile();
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
|
||||
{
|
||||
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
|
||||
|
||||
SupportedCommands = new List<string>
|
||||
{
|
||||
GeneralCommandType.VolumeDown.ToString(),
|
||||
GeneralCommandType.VolumeUp.ToString(),
|
||||
GeneralCommandType.Mute.ToString(),
|
||||
GeneralCommandType.Unmute.ToString(),
|
||||
GeneralCommandType.ToggleMute.ToString(),
|
||||
GeneralCommandType.SetVolume.ToString(),
|
||||
GeneralCommandType.SetAudioStreamIndex.ToString(),
|
||||
GeneralCommandType.SetSubtitleStreamIndex.ToString()
|
||||
},
|
||||
|
||||
SupportsMediaControl = true
|
||||
});
|
||||
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
_nonRendererUrls.Add(location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var controller = sessionInfo.SessionController as PlayToController;
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
var serverAddress = GetServerAddress(localIp);
|
||||
string accessToken = null;
|
||||
|
||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
|
||||
_sessionManager,
|
||||
_libraryManager,
|
||||
_logger,
|
||||
_dlnaManager,
|
||||
_userManager,
|
||||
_imageProcessor,
|
||||
serverAddress,
|
||||
accessToken,
|
||||
_deviceDiscovery,
|
||||
_userDataManager,
|
||||
_localization,
|
||||
_mediaSourceManager);
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
|
||||
_dlnaManager.GetDefaultProfile();
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
|
||||
{
|
||||
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
|
||||
|
||||
SupportedCommands = new List<string>
|
||||
{
|
||||
GeneralCommandType.VolumeDown.ToString(),
|
||||
GeneralCommandType.VolumeUp.ToString(),
|
||||
GeneralCommandType.Mute.ToString(),
|
||||
GeneralCommandType.Unmute.ToString(),
|
||||
GeneralCommandType.ToggleMute.ToString(),
|
||||
GeneralCommandType.SetVolume.ToString(),
|
||||
GeneralCommandType.SetAudioStreamIndex.ToString(),
|
||||
GeneralCommandType.SetSubtitleStreamIndex.ToString()
|
||||
},
|
||||
|
||||
SupportsMediaControl = true
|
||||
});
|
||||
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -156,6 +183,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
public void Dispose()
|
||||
{
|
||||
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
|
||||
|
||||
if (_clearNonRenderersTimer != null)
|
||||
{
|
||||
_clearNonRenderersTimer.Dispose();
|
||||
_clearNonRenderersTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Dlna.Common;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
public class SsdpHttpClient
|
||||
{
|
||||
private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
|
||||
private const string FriendlyName = "MediaBrowser";
|
||||
private const string FriendlyName = "Emby";
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
DeviceService service,
|
||||
string command,
|
||||
string postData,
|
||||
bool logRequest = true,
|
||||
string header = null)
|
||||
{
|
||||
var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
|
||||
var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header, logRequest)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
using (var stream = response.Content)
|
||||
|
@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
|
||||
|
@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
|
||||
|
@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
||||
string soapAction,
|
||||
string postData,
|
||||
string header = null)
|
||||
string header,
|
||||
bool logRequest)
|
||||
{
|
||||
if (!soapAction.StartsWith("\""))
|
||||
soapAction = "\"" + soapAction + "\"";
|
||||
|
@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
|
||||
|
|
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
[XmlRoot("Profile")]
|
||||
public class BubbleUpnpProfile : DefaultProfile
|
||||
{
|
||||
public BubbleUpnpProfile()
|
||||
{
|
||||
Name = "BubbleUPnp";
|
||||
|
||||
TimelineOffsetSeconds = 5;
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
ModelName = "BubbleUPnp",
|
||||
|
||||
Headers = new[]
|
||||
{
|
||||
new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
|
||||
}
|
||||
};
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "mp3",
|
||||
Type = DlnaProfileType.Audio,
|
||||
AudioCodec = "mp3"
|
||||
},
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "aac"
|
||||
},
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "jpeg",
|
||||
Type = DlnaProfileType.Photo
|
||||
}
|
||||
};
|
||||
|
||||
DirectPlayProfiles = new[]
|
||||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "mp3,flac,asf,off,oga,aac",
|
||||
Type = DlnaProfileType.Audio
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Type = DlnaProfileType.Photo,
|
||||
|
||||
Container = "jpeg,png,gif,bmp,tiff"
|
||||
}
|
||||
};
|
||||
|
||||
ResponseProfiles = new ResponseProfile[] { };
|
||||
|
||||
ContainerProfiles = new ContainerProfile[] { };
|
||||
|
||||
CodecProfiles = new CodecProfile[] { };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Model.Dlna;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MediaBrowser.Dlna.Profiles
|
||||
|
@ -75,6 +76,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Type = DlnaProfileType.Video
|
||||
}
|
||||
};
|
||||
|
||||
AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
|
||||
AddXmlRootAttribute("xmlns:dlna", "urn:schemas-dlna-org:device-1-0");
|
||||
}
|
||||
|
||||
public void AddXmlRootAttribute(string name, string value)
|
||||
{
|
||||
var atts = XmlRootAttributes ?? new XmlAttribute[] { };
|
||||
var list = atts.ToList();
|
||||
|
||||
list.Add(new XmlAttribute
|
||||
{
|
||||
Name = name,
|
||||
Value = value
|
||||
});
|
||||
|
||||
XmlRootAttributes = list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:pv",
|
||||
Value = "http://www.pv.com/pvns/"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
|
||||
|
||||
TimelineOffsetSeconds = 10;
|
||||
|
||||
|
|
|
@ -27,14 +27,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:sec",
|
||||
Value = "http://www.sec.co.kr/"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/");
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
|
|
@ -17,14 +17,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
ModelNumber = "BDP-2013"
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
ModelName = "Windows Media Player Sharing";
|
||||
ModelNumber = "3.0";
|
||||
|
|
|
@ -33,14 +33,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
ModelName = "Windows Media Player Sharing";
|
||||
ModelNumber = "3.0";
|
||||
|
|
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
AlbumArtPn = "JPEG_TN";
|
||||
|
||||
|
@ -47,6 +40,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
|
||||
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -293,6 +287,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
Value = "1080"
|
||||
},
|
||||
new ProfileCondition
|
||||
{
|
||||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.VideoFramerate,
|
||||
Value = "30"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
AlbumArtPn = "JPEG_TN";
|
||||
|
||||
|
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
ManufacturerUrl = "http://www.microsoft.com/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -310,6 +304,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
Value = "1080"
|
||||
},
|
||||
new ProfileCondition
|
||||
{
|
||||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.VideoFramerate,
|
||||
Value = "30"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
AlbumArtPn = "JPEG_TN";
|
||||
|
||||
|
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
ManufacturerUrl = "http://www.microsoft.com/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -250,6 +244,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
Value = "1080"
|
||||
},
|
||||
new ProfileCondition
|
||||
{
|
||||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.VideoFramerate,
|
||||
Value = "30"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new[]
|
||||
{
|
||||
new XmlAttribute
|
||||
{
|
||||
Name = "xmlns:av",
|
||||
Value = "urn:schemas-sony-com:av"
|
||||
}
|
||||
};
|
||||
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||
|
||||
AlbumArtPn = "JPEG_TN";
|
||||
|
||||
|
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
ManufacturerUrl = "http://www.microsoft.com/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -284,6 +278,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
Value = "1080"
|
||||
},
|
||||
new ProfileCondition
|
||||
{
|
||||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.VideoFramerate,
|
||||
Value = "30"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System.Xml.Serialization;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace MediaBrowser.Dlna.Profiles
|
||||
{
|
||||
[XmlRoot("Profile")]
|
||||
public class VlcProfile : DefaultProfile
|
||||
{
|
||||
public VlcProfile()
|
||||
{
|
||||
Name = "Vlc";
|
||||
|
||||
TimelineOffsetSeconds = 5;
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
ModelName = "Vlc",
|
||||
|
||||
Headers = new[]
|
||||
{
|
||||
new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
|
||||
}
|
||||
};
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "mp3",
|
||||
Type = DlnaProfileType.Audio,
|
||||
AudioCodec = "mp3"
|
||||
},
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "aac"
|
||||
},
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "jpeg",
|
||||
Type = DlnaProfileType.Photo
|
||||
}
|
||||
};
|
||||
|
||||
DirectPlayProfiles = new[]
|
||||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "mp3,flac,asf,off,oga,aac",
|
||||
Type = DlnaProfileType.Audio
|
||||
},
|
||||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Type = DlnaProfileType.Photo,
|
||||
|
||||
Container = "jpeg,png,gif,bmp,tiff"
|
||||
}
|
||||
};
|
||||
|
||||
ResponseProfiles = new ResponseProfile[] { };
|
||||
|
||||
ContainerProfiles = new ContainerProfile[] { };
|
||||
|
||||
CodecProfiles = new CodecProfile[] { };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Name = "WDTV Live";
|
||||
|
||||
TimelineOffsetSeconds = 5;
|
||||
IgnoreTranscodeByteRangeRequests = true;
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
|
|
|
@ -18,12 +18,13 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
|
||||
ModelNumber = "12.0";
|
||||
|
||||
FriendlyName = "${HostName} : 1";
|
||||
FriendlyName = "${HostName}: Emby:";
|
||||
|
||||
ModelUrl = "http://www.microsoft.com/";
|
||||
ModelUrl = "http://go.microsoft.com/fwlink/?LinkId=105926";
|
||||
Manufacturer = "Microsoft Corporation";
|
||||
ManufacturerUrl = "http://www.microsoft.com/";
|
||||
ManufacturerUrl = "http://www.microsoft.com";
|
||||
XDlnaDoc = "DMS-1.50";
|
||||
ModelDescription = null;
|
||||
|
||||
TimelineOffsetSeconds = 40;
|
||||
RequiresPlainFolders = true;
|
||||
|
@ -311,6 +312,9 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
XmlRootAttributes = new XmlAttribute[] { };
|
||||
AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
FriendlyName = "XboxOne",
|
||||
ModelName = "Xbox One",
|
||||
|
||||
Headers = new[]
|
||||
{
|
||||
|
|
53
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
53
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -27,7 +26,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
||||
<DirectPlayProfile container="avi,mp4" type="Video" />
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -32,7 +31,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||
</DirectPlayProfiles>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -33,7 +32,10 @@
|
|||
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>true</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="jpeg,jpg" type="Photo" />
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,7 +33,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp4,mkv,mpeg,ts" audioCodec="mp3,ac3,aac,he-aac,pcm" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
|
||||
|
|
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -33,7 +32,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -31,7 +30,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||
|
@ -33,7 +32,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
||||
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -35,6 +34,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -27,7 +26,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp4,mov" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,6 +33,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,6 +33,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -36,6 +35,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -36,6 +35,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
@ -79,6 +80,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -36,6 +35,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
@ -82,6 +83,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -36,6 +35,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
@ -67,6 +68,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -36,6 +35,8 @@
|
|||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
|
@ -72,6 +73,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -35,7 +34,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
|
|
53
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
53
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,7 +33,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
|
|
|
@ -8,14 +8,12 @@
|
|||
<HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
|
||||
</Headers>
|
||||
</Identification>
|
||||
<FriendlyName>${HostName} : 1</FriendlyName>
|
||||
<FriendlyName>${HostName}: Emby:</FriendlyName>
|
||||
<Manufacturer>Microsoft Corporation</Manufacturer>
|
||||
<ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
|
||||
<ManufacturerUrl>http://www.microsoft.com</ManufacturerUrl>
|
||||
<ModelName>Windows Media Player Sharing</ModelName>
|
||||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>12.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<ModelUrl>http://go.microsoft.com/fwlink/?LinkId=105926</ModelUrl>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,7 +32,9 @@
|
|||
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>true</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Xbox One</Name>
|
||||
<Identification>
|
||||
<FriendlyName>XboxOne</FriendlyName>
|
||||
<ModelName>Xbox One</ModelName>
|
||||
<Headers>
|
||||
<HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
|
||||
<HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
|
||||
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
@ -34,7 +33,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||
|
@ -33,7 +32,10 @@
|
|||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
||||
<XmlRootAttributes />
|
||||
<XmlRootAttributes>
|
||||
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||
<XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
||||
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
||||
|
|
|
@ -18,8 +18,9 @@ namespace MediaBrowser.Dlna.Server
|
|||
private readonly string _serverUdn;
|
||||
private readonly string _serverAddress;
|
||||
private readonly string _serverName;
|
||||
private readonly string _serverId;
|
||||
|
||||
public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName)
|
||||
public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName, string serverId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(serverUdn))
|
||||
{
|
||||
|
@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.Server
|
|||
_serverUdn = serverUdn;
|
||||
_serverAddress = serverAddress;
|
||||
_serverName = serverName;
|
||||
_serverId = serverId;
|
||||
}
|
||||
|
||||
private bool EnableAbsoluteUrls
|
||||
|
@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Server
|
|||
|
||||
builder.Append("<?xml version=\"1.0\"?>");
|
||||
|
||||
builder.Append("<root xmlns=\"urn:schemas-upnp-org:device-1-0\" xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"");
|
||||
builder.Append("<root");
|
||||
foreach (var att in _profile.XmlRootAttributes)
|
||||
{
|
||||
builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
|
||||
|
@ -72,7 +74,7 @@ namespace MediaBrowser.Dlna.Server
|
|||
builder.Append("<device>");
|
||||
AppendDeviceProperties(builder);
|
||||
|
||||
AppendIconList(builder);
|
||||
//AppendIconList(builder);
|
||||
AppendServiceList(builder);
|
||||
builder.Append("</device>");
|
||||
}
|
||||
|
@ -80,20 +82,37 @@ namespace MediaBrowser.Dlna.Server
|
|||
private void AppendDeviceProperties(StringBuilder builder)
|
||||
{
|
||||
builder.Append("<UDN>uuid:" + SecurityElement.Escape(_serverUdn) + "</UDN>");
|
||||
builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_profile.XDlnaCap))
|
||||
{
|
||||
builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
|
||||
}
|
||||
|
||||
builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">M-DMS-1.50</dlna:X_DLNADOC>");
|
||||
builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "</dlna:X_DLNADOC>");
|
||||
|
||||
|
||||
builder.Append("<friendlyName>" + SecurityElement.Escape(GetFriendlyName()) + "</friendlyName>");
|
||||
builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
|
||||
builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
|
||||
builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
|
||||
builder.Append("<modelName>" + SecurityElement.Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
|
||||
builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_profile.ModelDescription))
|
||||
{
|
||||
builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
|
||||
}
|
||||
|
||||
builder.Append("<modelNumber>" + SecurityElement.Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
|
||||
builder.Append("<modelURL>" + SecurityElement.Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
|
||||
builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber ?? string.Empty) + "</serialNumber>");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_profile.SerialNumber))
|
||||
{
|
||||
builder.Append("<serialNumber>" + SecurityElement.Escape(_serverId) + "</serialNumber>");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber) + "</serialNumber>");
|
||||
}
|
||||
|
||||
builder.Append("<presentationURL>" + SecurityElement.Escape(_serverAddress) + "</presentationURL>");
|
||||
|
||||
|
|
|
@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
LogRequest(request);
|
||||
}
|
||||
|
||||
var response = ProcessControlRequestInternal(request);
|
||||
|
||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
LogResponse(response);
|
||||
}
|
||||
|
|
|
@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
public EndPoint FromEndPoint { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
public bool IgnoreBindFailure { get; private set; }
|
||||
public bool EnableDebugLogging { get; private set; }
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure)
|
||||
public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure, bool enableDebugLogging)
|
||||
{
|
||||
Message = message;
|
||||
_logger = logger;
|
||||
EnableDebugLogging = enableDebugLogging;
|
||||
IgnoreBindFailure = ignoreBindFailure;
|
||||
FromEndPoint = fromEndPoint;
|
||||
ToEndPoint = toEndPoint;
|
||||
|
@ -27,59 +29,93 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
public void Send()
|
||||
{
|
||||
var msg = Encoding.ASCII.GetBytes(Message);
|
||||
try
|
||||
{
|
||||
var client = CreateSocket();
|
||||
|
||||
if (FromEndPoint != null)
|
||||
var socket = CreateSocket();
|
||||
|
||||
if (socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FromEndPoint != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
socket.Bind(FromEndPoint);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (EnableDebugLogging)
|
||||
{
|
||||
client.Bind(FromEndPoint);
|
||||
_logger.ErrorException("Error binding datagram socket", ex);
|
||||
}
|
||||
catch
|
||||
|
||||
if (!IgnoreBindFailure)
|
||||
{
|
||||
if (!IgnoreBindFailure) throw;
|
||||
CloseSocket(socket, false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
|
||||
try
|
||||
{
|
||||
socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
|
||||
{
|
||||
try
|
||||
{
|
||||
client.EndSend(result);
|
||||
socket.EndSend(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!IgnoreBindFailure)
|
||||
if (!IgnoreBindFailure || EnableDebugLogging)
|
||||
{
|
||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
CloseSocket(socket, true);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
||||
CloseSocket(socket, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseSocket(Socket socket, bool logError)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (logError && EnableDebugLogging)
|
||||
{
|
||||
_logger.ErrorException("Error closing datagram socket", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Socket CreateSocket()
|
||||
{
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
try
|
||||
{
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
|
||||
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
return socket;
|
||||
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
return socket;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error creating socket", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -142,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
args.EndPoint = endPoint;
|
||||
args.LocalIp = localIp;
|
||||
|
||||
TryCreateDevice(args);
|
||||
if (!_ssdpHandler.IsSelfNotification(args))
|
||||
{
|
||||
TryCreateDevice(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +186,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
}
|
||||
|
||||
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
|
||||
|
||||
}
|
||||
|
||||
private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
|
||||
|
@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
string nts;
|
||||
args.Headers.TryGetValue("NTS", out nts);
|
||||
|
||||
if (String.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (String.Equals(args.Method, "NOTIFY", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
EventHelper.FireEventIfNotNull(DeviceLeft, this, args, _logger);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string usn;
|
||||
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
||||
|
||||
string nt;
|
||||
if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
|
||||
|
||||
// Ignore when a device is indicating it's shutting down
|
||||
if (string.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to be able to download device description
|
||||
string location;
|
||||
if (!args.Headers.TryGetValue("Location", out location) ||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Dlna.Server;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
|
@ -16,7 +18,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Dlna.Ssdp
|
||||
{
|
||||
public class SsdpHandler : IDisposable
|
||||
public class SsdpHandler : IDisposable, ISsdpHandler
|
||||
{
|
||||
private Socket _socket;
|
||||
|
||||
|
@ -39,13 +41,39 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
private bool _isDisposed;
|
||||
private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
|
||||
|
||||
public SsdpHandler(ILogger logger, IServerConfigurationManager config, string serverSignature)
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_serverSignature = serverSignature;
|
||||
_appHost = appHost;
|
||||
|
||||
_config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
|
||||
_serverSignature = GenerateServerSignature();
|
||||
}
|
||||
|
||||
private string GenerateServerSignature()
|
||||
{
|
||||
var os = Environment.OSVersion;
|
||||
var pstring = os.Platform.ToString();
|
||||
switch (os.Platform)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
case PlatformID.Win32S:
|
||||
case PlatformID.Win32Windows:
|
||||
pstring = "WIN";
|
||||
break;
|
||||
}
|
||||
|
||||
return String.Format(
|
||||
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
|
||||
pstring,
|
||||
IntPtr.Size * 8,
|
||||
os.Version.Major,
|
||||
os.Version.Minor,
|
||||
_appHost.ApplicationVersion
|
||||
);
|
||||
}
|
||||
|
||||
void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
|
||||
|
@ -60,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
||||
{
|
||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var headers = args.Headers;
|
||||
var headers = args.Headers;
|
||||
string st;
|
||||
|
||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
|
||||
{
|
||||
TimeSpan delay = GetSearchDelay(headers);
|
||||
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
{
|
||||
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
||||
}
|
||||
|
||||
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
|
||||
string st;
|
||||
if (headers.TryGetValue("st", out st))
|
||||
{
|
||||
RespondToSearch(args.EndPoint, st);
|
||||
}
|
||||
RespondToSearch(args.EndPoint, st);
|
||||
}
|
||||
|
||||
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
||||
|
@ -117,7 +142,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
values["MX"] = "3";
|
||||
|
||||
// UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
|
||||
SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 1);
|
||||
SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 2);
|
||||
}
|
||||
|
||||
public void SendDatagram(string header,
|
||||
|
@ -138,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||
var queued = false;
|
||||
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
for (var i = 0; i < sendCount; i++)
|
||||
{
|
||||
var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure);
|
||||
var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure, enableDebugLogging);
|
||||
|
||||
if (_messageQueue.Count == 0)
|
||||
{
|
||||
|
@ -184,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
||||
{
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
{
|
||||
_logger.Debug("RespondToSearch");
|
||||
}
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
var isLogged = false;
|
||||
|
||||
const string header = "HTTP/1.1 200 OK";
|
||||
|
||||
|
@ -196,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!isLogged)
|
||||
{
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug("Responding to search from {0} for {1}", endpoint, deviceType);
|
||||
}
|
||||
isLogged = true;
|
||||
}
|
||||
|
||||
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
values["CACHE-CONTROL"] = "max-age = 600";
|
||||
|
@ -210,7 +245,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
|
||||
//SendDatagram(header, values, endpoint, null, true);
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
|
||||
}
|
||||
|
@ -288,7 +323,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
var received = (byte[])result.AsyncState;
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug(Encoding.ASCII.GetString(received));
|
||||
}
|
||||
|
@ -296,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
var args = SsdpHelper.ParseSsdpResponse(received);
|
||||
args.EndPoint = endpoint;
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (IsSelfNotification(args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||
var headerText = string.Join(",", headerTexts.ToArray());
|
||||
|
@ -317,6 +359,44 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
}
|
||||
}
|
||||
|
||||
internal bool IsSelfNotification(SsdpMessageEventArgs args)
|
||||
{
|
||||
// Avoid responding to self search messages
|
||||
//string serverId;
|
||||
//if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) &&
|
||||
// string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// return true;
|
||||
//}
|
||||
|
||||
string server;
|
||||
args.Headers.TryGetValue("SERVER", out server);
|
||||
|
||||
if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
//string usn;
|
||||
//args.Headers.TryGetValue("USN", out usn);
|
||||
|
||||
//if (string.IsNullOrWhiteSpace(usn))
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//_logger.Debug("IsSelfNotification test: " + usn);
|
||||
|
||||
//return RegisteredDevices.Any(i =>
|
||||
//{
|
||||
// var isSameDevice = string.Equals(usn, i.USN, StringComparison.OrdinalIgnoreCase) ||
|
||||
// i.USN.IndexOf(usn, StringComparison.OrdinalIgnoreCase) != 1 ||
|
||||
// usn.IndexOf(i.USN, StringComparison.OrdinalIgnoreCase) != 1;
|
||||
|
||||
// return isSameDevice;
|
||||
//});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
||||
|
@ -371,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private void NotifyAll()
|
||||
{
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug("Sending alive notifications");
|
||||
}
|
||||
foreach (var d in RegisteredDevices)
|
||||
{
|
||||
NotifyDevice(d, "alive", 1);
|
||||
NotifyDevice(d, "alive", 1, enableDebugLogging);
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyDevice(UpnpDevice dev, string type, int sendCount)
|
||||
private void NotifyDevice(UpnpDevice dev, string type, int sendCount, bool logMessage)
|
||||
{
|
||||
const string header = "NOTIFY * HTTP/1.1";
|
||||
|
||||
|
@ -396,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
values["NT"] = dev.Type;
|
||||
values["USN"] = dev.USN;
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (logMessage)
|
||||
{
|
||||
_logger.Debug("{0} said {1}", dev.USN, type);
|
||||
}
|
||||
|
@ -429,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
foreach (var d in dl.ToList())
|
||||
{
|
||||
NotifyDevice(d, "byebye", 2);
|
||||
NotifyDevice(d, "byebye", 2, true);
|
||||
}
|
||||
|
||||
_logger.Debug("Unregistered mount {0}", uuid);
|
||||
|
@ -440,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
private int _aliveNotifierIntervalMs;
|
||||
private void ReloadAliveNotifier()
|
||||
{
|
||||
if (!_config.GetDlnaConfiguration().BlastAliveMessages)
|
||||
var config = _config.GetDlnaConfiguration();
|
||||
|
||||
if (!config.BlastAliveMessages)
|
||||
{
|
||||
DisposeNotificationTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
|
||||
var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
|
||||
|
||||
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
@ -34,7 +35,8 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
return new SsdpMessageEventArgs
|
||||
{
|
||||
Method = method,
|
||||
Headers = headers
|
||||
Headers = headers,
|
||||
Message = data
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
|
||||
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
|
||||
}
|
||||
|
||||
// If a fixed width was requested
|
||||
|
@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
|
||||
// If a max width was requested
|
||||
else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
||||
else if (request.MaxWidth.HasValue)
|
||||
{
|
||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||
|
||||
|
@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
|
||||
// If a max height was requested
|
||||
else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
||||
else if (request.MaxHeight.HasValue)
|
||||
{
|
||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
||||
}
|
||||
|
||||
else if (request.MaxWidth.HasValue ||
|
||||
request.MaxHeight.HasValue ||
|
||||
request.Width.HasValue ||
|
||||
request.Height.HasValue)
|
||||
{
|
||||
if (state.VideoStream != null)
|
||||
{
|
||||
// Need to perform calculations manually
|
||||
|
||||
// Try to account for bad media info
|
||||
var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
|
||||
var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
|
||||
|
||||
var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
||||
|
||||
var manualWidthParam = outputSize.Width.ToString(UsCulture);
|
||||
var manualHeightParam = outputSize.Height.ToString(UsCulture);
|
||||
|
||||
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
|
||||
}
|
||||
}
|
||||
|
||||
var output = string.Empty;
|
||||
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||
|
|
|
@ -716,8 +716,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
profile.GetVideoMediaProfile(outputContainer,
|
||||
audioCodec,
|
||||
videoCodec,
|
||||
state.OutputAudioBitrate,
|
||||
state.OutputAudioChannels,
|
||||
state.OutputWidth,
|
||||
state.OutputHeight,
|
||||
state.TargetVideoBitDepth,
|
||||
|
|
|
@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ffProbeResourcePool.Release();
|
||||
|
||||
_logger.ErrorException("Error starting ffprobe", ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
||||
|
||||
if (result != null)
|
||||
try
|
||||
{
|
||||
if (result.streams != null)
|
||||
{
|
||||
// Normalize aspect ratio if invalid
|
||||
foreach (var stream in result.streams)
|
||||
{
|
||||
if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stream.display_aspect_ratio = string.Empty;
|
||||
}
|
||||
if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stream.sample_aspect_ratio = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
||||
|
||||
if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
|
||||
{
|
||||
foreach (var stream in mediaInfo.MediaStreams)
|
||||
{
|
||||
if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
|
||||
// .ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting key frame interval", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mediaInfo;
|
||||
StartProcess(processWrapper);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ffProbeResourcePool.Release();
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_ffProbeResourcePool.Release();
|
||||
_logger.ErrorException("Error starting ffprobe", ex);
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
if (result.streams != null)
|
||||
{
|
||||
// Normalize aspect ratio if invalid
|
||||
foreach (var stream in result.streams)
|
||||
{
|
||||
if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stream.display_aspect_ratio = string.Empty;
|
||||
}
|
||||
if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
stream.sample_aspect_ratio = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
||||
|
||||
if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
|
||||
{
|
||||
foreach (var stream in mediaInfo.MediaStreams)
|
||||
{
|
||||
if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
|
||||
// .ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting key frame interval", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mediaInfo;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_ffProbeResourcePool.Release();
|
||||
}
|
||||
}
|
||||
|
||||
throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
|
||||
|
@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
StartProcess(processWrapper);
|
||||
|
||||
var lines = new List<int>();
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
process.BeginErrorReadLine();
|
||||
StartProcess(processWrapper);
|
||||
|
||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
var lines = new List<int>();
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
}
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
return lines;
|
||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
|
||||
|
@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
bool ranToCompletion;
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
bool ranToCompletion;
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
try
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
|
||||
#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);
|
||||
// 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();
|
||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
ranToCompletion = process.WaitForExit(10000);
|
||||
ranToCompletion = process.WaitForExit(10000);
|
||||
|
||||
if (!ranToCompletion)
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
StopProcess(processWrapper, 1000, false);
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopProcess(processWrapper, 1000, false);
|
||||
resourcePool.Release();
|
||||
}
|
||||
|
||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||
|
||||
if (exitCode == -1 || memoryStream.Length == 0)
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
|
||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
|
||||
|
||||
_logger.Error(msg);
|
||||
|
||||
throw new ApplicationException(msg);
|
||||
}
|
||||
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
}
|
||||
finally
|
||||
{
|
||||
resourcePool.Release();
|
||||
}
|
||||
|
||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||
|
||||
if (exitCode == -1 || memoryStream.Length == 0)
|
||||
{
|
||||
memoryStream.Dispose();
|
||||
|
||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
|
||||
|
||||
_logger.Error(msg);
|
||||
|
||||
throw new ApplicationException(msg);
|
||||
}
|
||||
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
public string GetTimeParameter(long ticks)
|
||||
|
@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
bool ranToCompletion = false;
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
|
||||
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
|
||||
// but we still need to detect if the process hangs.
|
||||
// Making the assumption that as long as new jpegs are showing up, everything is good.
|
||||
|
||||
bool isResponsive = true;
|
||||
int lastCount = 0;
|
||||
|
||||
while (isResponsive)
|
||||
try
|
||||
{
|
||||
if (process.WaitForExit(30000))
|
||||
StartProcess(processWrapper);
|
||||
|
||||
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
|
||||
// but we still need to detect if the process hangs.
|
||||
// Making the assumption that as long as new jpegs are showing up, everything is good.
|
||||
|
||||
bool isResponsive = true;
|
||||
int lastCount = 0;
|
||||
|
||||
while (isResponsive)
|
||||
{
|
||||
ranToCompletion = true;
|
||||
break;
|
||||
if (process.WaitForExit(30000))
|
||||
{
|
||||
ranToCompletion = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var jpegCount = Directory.GetFiles(targetDirectory)
|
||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
isResponsive = (jpegCount > lastCount);
|
||||
lastCount = jpegCount;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var jpegCount = Directory.GetFiles(targetDirectory)
|
||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
isResponsive = (jpegCount > lastCount);
|
||||
lastCount = jpegCount;
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
StopProcess(processWrapper, 1000, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ranToCompletion)
|
||||
finally
|
||||
{
|
||||
StopProcess(processWrapper, 1000, false);
|
||||
resourcePool.Release();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
resourcePool.Release();
|
||||
}
|
||||
|
||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||
|
||||
if (exitCode == -1)
|
||||
{
|
||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
||||
if (exitCode == -1)
|
||||
{
|
||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
||||
|
||||
_logger.Error(msg);
|
||||
_logger.Error(msg);
|
||||
|
||||
throw new ApplicationException(msg);
|
||||
throw new ApplicationException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
}
|
||||
|
||||
private class ProcessWrapper
|
||||
private class ProcessWrapper : IDisposable
|
||||
{
|
||||
public readonly Process Process;
|
||||
public bool HasExited;
|
||||
|
@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
process.Dispose();
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
private readonly object _syncLock = new object();
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (Process != null)
|
||||
{
|
||||
Process.Exited -= Process_Exited;
|
||||
Process.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
|
|
@ -1499,5 +1499,11 @@ namespace MediaBrowser.Model.ApiClient
|
|||
/// <param name="itemIds">The item ids.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
|
||||
/// <summary>
|
||||
/// Gets the supported bitrate.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<System.Int32>.</returns>
|
||||
Task<int> GetSupportedBitrate(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// different directories and files.
|
||||
/// </summary>
|
||||
/// <value>The file watcher delay.</value>
|
||||
public int RealtimeMonitorDelay { get; set; }
|
||||
public int RealtimeLibraryMonitorDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
||||
|
@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
// 5 minutes
|
||||
MinResumeDurationSeconds = 300;
|
||||
|
||||
RealtimeMonitorDelay = 30;
|
||||
RealtimeLibraryMonitorDelay = 40;
|
||||
|
||||
EnableInternetProviders = true;
|
||||
FindInternetTrailers = true;
|
||||
|
@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
|
|||
"Chromecast",
|
||||
"iOS",
|
||||
"Unknown app",
|
||||
"MediaPortal",
|
||||
"Media Portal",
|
||||
"iPad",
|
||||
"iPhone",
|
||||
"Windows Phone"
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
public string[] DisplayChannelsWithinViews { get; set; }
|
||||
|
||||
public string[] ExcludeFoldersFromGrouping { get; set; }
|
||||
public string[] GroupedFolders { get; set; }
|
||||
|
||||
public SubtitlePlaybackMode SubtitleMode { get; set; }
|
||||
public bool DisplayCollectionsView { get; set; }
|
||||
|
@ -62,12 +63,13 @@ namespace MediaBrowser.Model.Configuration
|
|||
OrderedViews = new string[] { };
|
||||
DisplayChannelsWithinViews = new string[] { };
|
||||
|
||||
ExcludeFoldersFromGrouping = new string[] { };
|
||||
PlainFolderViews = new string[] { };
|
||||
DisplayCollectionsView = true;
|
||||
|
||||
IncludeTrailersInSuggestions = true;
|
||||
EnableCinemaMode = true;
|
||||
|
||||
GroupedFolders = new string[] { };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
|
|||
[XmlAttribute("codec")]
|
||||
public string Codec { get; set; }
|
||||
|
||||
[XmlAttribute("container")]
|
||||
public string Container { get; set; }
|
||||
|
||||
public CodecProfile()
|
||||
{
|
||||
Conditions = new ProfileCondition[] {};
|
||||
|
@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
|
|||
return list;
|
||||
}
|
||||
|
||||
public bool ContainsCodec(string codec)
|
||||
public List<string> GetContainers()
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
foreach (string i in (Container ?? string.Empty).Split(','))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(i)) list.Add(i);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private bool ContainsContainer(string container)
|
||||
{
|
||||
List<string> containers = GetContainers();
|
||||
|
||||
return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
|
||||
}
|
||||
|
||||
public bool ContainsCodec(string codec, string container)
|
||||
{
|
||||
if (!ContainsContainer(container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<string> codecs = GetCodecs();
|
||||
|
||||
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
||||
|
|
|
@ -7,8 +7,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
public class ConditionProcessor
|
||||
{
|
||||
public bool IsVideoConditionSatisfied(ProfileCondition condition,
|
||||
int? audioBitrate,
|
||||
int? audioChannels,
|
||||
int? width,
|
||||
int? height,
|
||||
int? bitDepth,
|
||||
|
@ -44,10 +42,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
return IsConditionSatisfied(condition, videoProfile);
|
||||
case ProfileConditionValue.PacketLength:
|
||||
return IsConditionSatisfied(condition, packetLength);
|
||||
case ProfileConditionValue.AudioBitrate:
|
||||
return IsConditionSatisfied(condition, audioBitrate);
|
||||
case ProfileConditionValue.AudioChannels:
|
||||
return IsConditionSatisfied(condition, audioChannels);
|
||||
case ProfileConditionValue.VideoBitDepth:
|
||||
return IsConditionSatisfied(condition, bitDepth);
|
||||
case ProfileConditionValue.VideoBitrate:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Model.MediaInfo;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
|
@ -105,8 +106,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
int? height,
|
||||
int? bitDepth,
|
||||
int? videoBitrate,
|
||||
int? audioChannels,
|
||||
int? audioBitrate,
|
||||
TransportStreamTimestamp timestamp,
|
||||
bool isDirectStream,
|
||||
long? runtimeTicks,
|
||||
|
@ -147,8 +146,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
|
||||
audioCodec,
|
||||
videoCodec,
|
||||
audioBitrate,
|
||||
audioChannels,
|
||||
width,
|
||||
height,
|
||||
bitDepth,
|
||||
|
@ -168,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
||||
{
|
||||
orgPnValues.Add(mediaProfile.OrgPn);
|
||||
orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
public string ModelNumber { get; set; }
|
||||
public string ModelUrl { get; set; }
|
||||
public string SerialNumber { get; set; }
|
||||
public bool IgnoreTranscodeByteRangeRequests { get; set; }
|
||||
|
||||
public bool EnableAlbumArtInDidl { get; set; }
|
||||
public bool EnableSingleAlbumArtLimit { get; set; }
|
||||
|
@ -272,8 +271,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
public ResponseProfile GetVideoMediaProfile(string container,
|
||||
string audioCodec,
|
||||
string videoCodec,
|
||||
int? audioBitrate,
|
||||
int? audioChannels,
|
||||
int? width,
|
||||
int? height,
|
||||
int? bitDepth,
|
||||
|
@ -321,7 +318,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
var anyOff = false;
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
{
|
||||
anyOff = true;
|
||||
break;
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
|
||||
if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
|
||||
{
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
|
||||
if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
|
||||
{
|
||||
audioCodecProfiles.Add(i);
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
|
||||
if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
|
||||
{
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
|
@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
|
||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
|
||||
{
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
|
@ -578,7 +578,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
// Check container conditions
|
||||
foreach (ProfileCondition i in conditions)
|
||||
{
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
{
|
||||
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
||||
|
||||
|
@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
conditions = new List<ProfileCondition>();
|
||||
foreach (CodecProfile i in profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
|
||||
if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
|
||||
{
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
|
@ -611,7 +611,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
foreach (ProfileCondition i in conditions)
|
||||
{
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
|
||||
{
|
||||
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
||||
|
||||
|
@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
conditions = new List<ProfileCondition>();
|
||||
foreach (CodecProfile i in profile.CodecProfiles)
|
||||
{
|
||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
|
||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
|
||||
{
|
||||
foreach (ProfileCondition c in i.Conditions)
|
||||
{
|
||||
|
|
|
@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
var hasChanges = false;
|
||||
|
||||
var images = providers.OfType<ILocalImageFileProvider>()
|
||||
.SelectMany(i => i.GetImages(item, directoryService))
|
||||
.ToList();
|
||||
|
||||
if (MergeImages(item, images))
|
||||
if (!(item is Photo))
|
||||
{
|
||||
hasChanges = true;
|
||||
var images = providers.OfType<ILocalImageFileProvider>()
|
||||
.SelectMany(i => i.GetImages(item, directoryService))
|
||||
.ToList();
|
||||
|
||||
if (MergeImages(item, images))
|
||||
{
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
|
@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
|
|||
var changed = false;
|
||||
|
||||
var newImages = images.Where(i => i.Type == type).ToList();
|
||||
if (newImages.Count > 0)
|
||||
{
|
||||
var newImageFileInfos = images.Where(i => i.Type == type)
|
||||
|
||||
var newImageFileInfos = newImages
|
||||
.Select(i => i.FileInfo)
|
||||
.ToList();
|
||||
|
||||
if (newImageFileInfos.Count > 0)
|
||||
{
|
||||
if (item.AddImages(type, newImageFileInfos))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (item.AddImages(type, newImageFileInfos))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
|
|
@ -14,6 +14,15 @@ namespace MediaBrowser.Providers.Manager
|
|||
bool replaceData,
|
||||
bool mergeMetadataSettings)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException("target");
|
||||
}
|
||||
|
||||
if (!lockedFields.Contains(MetadataFields.Name))
|
||||
{
|
||||
if (replaceData || string.IsNullOrEmpty(target.Name))
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
|
||||
private string GetAudioImagePath(Audio item)
|
||||
{
|
||||
var album = item.Parent as MusicAlbum;
|
||||
var album = item.AlbumEntity;
|
||||
|
||||
var filename = item.Album ?? string.Empty;
|
||||
filename += string.Join(",", item.Artists.ToArray());
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
|
|||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient)
|
||||
public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
Current = this;
|
||||
}
|
||||
|
||||
|
@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
try
|
||||
{
|
||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
|
||||
cancellationToken);
|
||||
result.HasMetadata = result.Item != null;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
|
@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
|
|||
// Don't fail the provider because this will just keep on going and going.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("No series identity found for {0}", searchInfo.Name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
||||
usingAbsoluteData = true;
|
||||
success = true;
|
||||
}
|
||||
|
||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
||||
|
@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
|
|||
episodeNumber++;
|
||||
}
|
||||
|
||||
return success ? episode : null;
|
||||
return episode;
|
||||
}
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
|
|
@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
{
|
||||
dto.Album = audio.Album;
|
||||
|
||||
var albumParent = audio.FindParent<MusicAlbum>();
|
||||
var albumParent = audio.AlbumEntity;
|
||||
|
||||
if (albumParent != null)
|
||||
{
|
||||
|
@ -1208,15 +1208,6 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
//}
|
||||
}
|
||||
|
||||
var album = item as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
dto.SoundtrackIds = album.SoundtrackIds
|
||||
.Select(i => i.ToString("N"))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var hasArtist = item as IHasArtist;
|
||||
if (hasArtist != null)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using Mono.Nat;
|
||||
|
@ -7,6 +8,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -17,15 +19,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ISsdpHandler _ssdp;
|
||||
|
||||
private Timer _timer;
|
||||
private bool _isStarted;
|
||||
|
||||
public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config)
|
||||
public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, ISsdpHandler ssdp)
|
||||
{
|
||||
_logger = logmanager.GetLogger("PortMapper");
|
||||
_appHost = appHost;
|
||||
_config = config;
|
||||
_ssdp = ssdp;
|
||||
}
|
||||
|
||||
private string _lastConfigIdentifier;
|
||||
|
@ -75,10 +79,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
private void Start()
|
||||
{
|
||||
_logger.Debug("Starting NAT discovery");
|
||||
//NatUtility.EnabledProtocols = new List<NatProtocol>
|
||||
//{
|
||||
// NatProtocol.Pmp
|
||||
//};
|
||||
NatUtility.EnabledProtocols = new List<NatProtocol>
|
||||
{
|
||||
NatProtocol.Pmp
|
||||
};
|
||||
NatUtility.DeviceFound += NatUtility_DeviceFound;
|
||||
|
||||
// Mono.Nat does never rise this event. The event is there however it is useless.
|
||||
|
@ -93,11 +97,23 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
|
||||
_timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
||||
|
||||
_ssdp.MessageReceived += _ssdp_MessageReceived;
|
||||
|
||||
_lastConfigIdentifier = GetConfigIdentifier();
|
||||
|
||||
_isStarted = true;
|
||||
}
|
||||
|
||||
void _ssdp_MessageReceived(object sender, SsdpMessageEventArgs e)
|
||||
{
|
||||
var endpoint = e.EndPoint as IPEndPoint;
|
||||
|
||||
if (endpoint != null && e.LocalIp != null)
|
||||
{
|
||||
NatUtility.Handle(e.LocalIp, e.Message, endpoint, NatProtocol.Upnp);
|
||||
}
|
||||
}
|
||||
|
||||
void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
var ex = e.ExceptionObject as Exception;
|
||||
|
@ -183,6 +199,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
_timer = null;
|
||||
}
|
||||
|
||||
_ssdp.MessageReceived -= _ssdp_MessageReceived;
|
||||
|
||||
try
|
||||
{
|
||||
// This is not a significant improvement
|
||||
|
|
|
@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Extensions;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Naming.IO;
|
||||
using MediaBrowser.Server.Implementations.Library;
|
||||
using MediaBrowser.Server.Implementations.Logging;
|
||||
using System;
|
||||
|
@ -60,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
|||
var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
|
||||
var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
|
||||
|
||||
var episodeInfo = resolver.Resolve(path, FileInfoType.File) ??
|
||||
var episodeInfo = resolver.Resolve(path, false) ??
|
||||
new Naming.TV.EpisodeInfo();
|
||||
|
||||
var seriesName = episodeInfo.SeriesName;
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
|
||||
// Seeing long delays in some situations, especially over the network.
|
||||
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
|
||||
await Task.Delay(1500).ConfigureAwait(false);
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
string val;
|
||||
_tempIgnoredPaths.TryRemove(path, out val);
|
||||
|
@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
{
|
||||
if (_updateTimer == null)
|
||||
{
|
||||
_updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||
_updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||
_updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +560,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
/// <returns>Task.</returns>
|
||||
private async Task ProcessPathChanges(List<string> paths)
|
||||
{
|
||||
var itemsToRefresh = paths.Select(Path.GetDirectoryName)
|
||||
var itemsToRefresh = paths
|
||||
.Select(GetAffectedBaseItem)
|
||||
.Where(item => item != null)
|
||||
.Distinct()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using Interfaces.IO;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Common.ScheduledTasks;
|
||||
|
@ -17,7 +18,6 @@ using MediaBrowser.Model.Entities;
|
|||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Naming.Audio;
|
||||
using MediaBrowser.Naming.Common;
|
||||
using MediaBrowser.Naming.IO;
|
||||
using MediaBrowser.Naming.TV;
|
||||
using MediaBrowser.Naming.Video;
|
||||
using MediaBrowser.Server.Implementations.Library.Validators;
|
||||
|
@ -1594,6 +1594,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
||||
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
|
||||
|
||||
public async Task<UserView> GetNamedView(User user,
|
||||
string name,
|
||||
string viewType,
|
||||
|
@ -1645,13 +1647,18 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
if (!refresh && item != null)
|
||||
{
|
||||
refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
|
||||
refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
|
||||
}
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
|
||||
_providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
|
||||
_providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
|
||||
{
|
||||
// Not sure why this is necessary but need to figure it out
|
||||
// View images are not getting utilized without this
|
||||
ForceSave = true
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -1731,7 +1738,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
|
@ -1767,14 +1774,13 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
var resolver = new EpisodeResolver(GetNamingOptions(),
|
||||
new PatternsLogger());
|
||||
|
||||
var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
|
||||
FileInfoType.Directory :
|
||||
FileInfoType.File;
|
||||
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
|
||||
episode.VideoType == VideoType.HdDvd;
|
||||
|
||||
var locationType = episode.LocationType;
|
||||
|
||||
var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
|
||||
resolver.Resolve(episode.Path, fileType) :
|
||||
resolver.Resolve(episode.Path, isFolder) :
|
||||
new Naming.TV.EpisodeInfo();
|
||||
|
||||
if (episodeInfo == null)
|
||||
|
@ -1928,10 +1934,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
|
||||
|
||||
var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
|
||||
var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
|
||||
{
|
||||
FullName = i.FullName,
|
||||
Type = GetFileType(i)
|
||||
Id = i.FullName,
|
||||
IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
|
||||
}).ToList());
|
||||
|
||||
|
@ -1962,16 +1968,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
}).OrderBy(i => i.Path).ToList();
|
||||
}
|
||||
|
||||
private FileInfoType GetFileType(FileSystemInfo info)
|
||||
{
|
||||
if ((info.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
{
|
||||
return FileInfoType.Directory;
|
||||
}
|
||||
|
||||
return FileInfoType.File;
|
||||
}
|
||||
|
||||
public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
|
||||
{
|
||||
var files = fileSystemChildren.OfType<DirectoryInfo>()
|
||||
|
@ -1981,10 +1977,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
|
||||
|
||||
var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
|
||||
var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
|
||||
{
|
||||
FullName = i.FullName,
|
||||
Type = GetFileType(i)
|
||||
Id = i.FullName,
|
||||
IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||
|
||||
}).ToList());
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user