Merge pull request #1098 from MediaBrowser/dev

3.0.5607.0
This commit is contained in:
Luke 2015-05-08 15:49:26 -04:00
commit b2cbe8b4e1
193 changed files with 8219 additions and 6630 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,9 @@
using System;
namespace MediaBrowser.Controller.Dlna
{
public interface ISsdpHandler
{
event EventHandler<SsdpMessageEventArgs> MessageReceived;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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[] { };
}
}
}

View File

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

View File

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

View File

@ -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[]
{

View File

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

View File

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

View File

@ -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"
}
}
},

View File

@ -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"
}
}
},

View File

@ -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"
}
}
},

View File

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

View 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[] { };
}
}
}

View File

@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
Name = "WDTV Live";
TimelineOffsetSeconds = 5;
IgnoreTranscodeByteRangeRequests = true;
Identification = new DeviceIdentification
{

View File

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

View File

@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles
Identification = new DeviceIdentification
{
FriendlyName = "XboxOne",
ModelName = "Xbox One",
Headers = new[]
{

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -716,8 +716,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
profile.GetVideoMediaProfile(outputContainer,
audioCodec,
videoCodec,
state.OutputAudioBitrate,
state.OutputAudioChannels,
state.OutputWidth,
state.OutputHeight,
state.TargetVideoBitDepth,

View File

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

View File

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

View File

@ -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&lt;System.Int32&gt;.</returns>
Task<int> GetSupportedBitrate(CancellationToken cancellationToken);
}
}

View File

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

View File

@ -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[] { };
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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