mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
commit
b2cbe8b4e1
@ -648,10 +648,8 @@ namespace MediaBrowser.Api.Images
|
|||||||
|
|
||||||
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
||||||
|
|
||||||
var clientFormats = GetClientSupportedFormats();
|
|
||||||
|
|
||||||
if (serverFormats.Contains(ImageFormat.Webp) &&
|
if (serverFormats.Contains(ImageFormat.Webp) &&
|
||||||
clientFormats.Contains(ImageFormat.Webp))
|
GetClientSupportedFormats().Contains(ImageFormat.Webp))
|
||||||
{
|
{
|
||||||
return ImageFormat.Webp;
|
return ImageFormat.Webp;
|
||||||
}
|
}
|
||||||
|
@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
|
|||||||
: (Folder)_libraryManager.RootFolder)
|
: (Folder)_libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(request.Id);
|
: _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var originalItem = item;
|
|
||||||
|
|
||||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||||
{
|
{
|
||||||
item = item.Parent;
|
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 dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
|
|||||||
: (Folder)_libraryManager.RootFolder)
|
: (Folder)_libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(request.Id);
|
: _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var originalItem = item;
|
|
||||||
|
|
||||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||||
{
|
{
|
||||||
item = item.Parent;
|
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 dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
|
|||||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||||
protected IZipClient ZipClient { get; private set; }
|
protected IZipClient ZipClient { get; private set; }
|
||||||
|
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||||
/// </summary>
|
/// </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;
|
ZipClient = zipClient;
|
||||||
MediaSourceManager = mediaSourceManager;
|
MediaSourceManager = mediaSourceManager;
|
||||||
DeviceManager = deviceManager;
|
DeviceManager = deviceManager;
|
||||||
@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
var maxHeightParam = request.MaxHeight.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
|
// If a fixed width was requested
|
||||||
@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If a max width was requested
|
// 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);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
|
|
||||||
@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If a max height was requested
|
// 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);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
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))
|
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
filters[filters.Count - 1] += ":flags=fast_bilinear";
|
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.
|
// 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);
|
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);
|
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.ErrorException("Error reading ffmpeg log", ex);
|
Logger.ErrorException("Error reading ffmpeg log", ex);
|
||||||
@ -2033,8 +2018,6 @@ namespace MediaBrowser.Api.Playback
|
|||||||
profile.GetVideoMediaProfile(state.OutputContainer,
|
profile.GetVideoMediaProfile(state.OutputContainer,
|
||||||
audioCodec,
|
audioCodec,
|
||||||
videoCodec,
|
videoCodec,
|
||||||
state.OutputAudioBitrate,
|
|
||||||
state.OutputAudioChannels,
|
|
||||||
state.OutputWidth,
|
state.OutputWidth,
|
||||||
state.OutputHeight,
|
state.OutputHeight,
|
||||||
state.TargetVideoBitDepth,
|
state.TargetVideoBitDepth,
|
||||||
@ -2121,8 +2104,6 @@ namespace MediaBrowser.Api.Playback
|
|||||||
state.OutputHeight,
|
state.OutputHeight,
|
||||||
state.TargetVideoBitDepth,
|
state.TargetVideoBitDepth,
|
||||||
state.OutputVideoBitrate,
|
state.OutputVideoBitrate,
|
||||||
state.OutputAudioBitrate,
|
|
||||||
state.OutputAudioChannels,
|
|
||||||
state.TargetTimestamp,
|
state.TargetTimestamp,
|
||||||
isStaticallyStreamed,
|
isStaticallyStreamed,
|
||||||
state.RunTimeTicks,
|
state.RunTimeTicks,
|
||||||
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
|||||||
|
|
||||||
public class MpegDashService : BaseHlsService
|
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;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback.Hls
|
namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseHlsService : BaseStreamingService
|
public abstract class BaseHlsService : BaseStreamingService
|
||||||
{
|
{
|
||||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using MediaBrowser.Model.Dlna;
|
|||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
|
|
||||||
public class DynamicHlsService : BaseHlsService
|
public class DynamicHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, 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;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
|
|||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoHlsService : BaseHlsService
|
public class VideoHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,16 +18,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
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")]
|
[Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
|
||||||
public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
|
public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
|
||||||
{
|
{
|
||||||
@ -55,6 +45,19 @@ namespace MediaBrowser.Api.Playback
|
|||||||
public string LiveStreamId { get; set; }
|
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]
|
[Authenticated]
|
||||||
public class MediaInfoService : BaseApiService
|
public class MediaInfoService : BaseApiService
|
||||||
{
|
{
|
||||||
@ -73,13 +76,19 @@ namespace MediaBrowser.Api.Playback
|
|||||||
_networkManager = networkManager;
|
_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);
|
var bytes = new byte[request.Size];
|
||||||
return ToOptimizedResult(result);
|
|
||||||
|
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);
|
var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
|
||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
|||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioService : BaseProgressiveStreamingService
|
public class AudioService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
|
|||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
protected readonly IImageProcessor ImageProcessor;
|
protected readonly IImageProcessor ImageProcessor;
|
||||||
protected readonly IHttpClient HttpClient;
|
protected readonly IHttpClient HttpClient;
|
||||||
|
|
||||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, 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;
|
ImageProcessor = imageProcessor;
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
|
|||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoService : BaseProgressiveStreamingService
|
public class VideoService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Subtitles
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
|
[Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
|
||||||
|
[Authenticated]
|
||||||
public class GetSubtitlePlaylist
|
public class GetSubtitlePlaylist
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -48,9 +48,9 @@
|
|||||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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>
|
<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>
|
||||||
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
<Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
@ -58,11 +58,8 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
<HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||||
</Reference>
|
<Private>True</Private>
|
||||||
<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>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
@ -6,16 +6,29 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Implementations.Networking
|
namespace MediaBrowser.Common.Implementations.Networking
|
||||||
{
|
{
|
||||||
public abstract class BaseNetworkManager
|
public abstract class BaseNetworkManager
|
||||||
{
|
{
|
||||||
protected ILogger Logger { get; private set; }
|
protected ILogger Logger { get; private set; }
|
||||||
|
private Timer _clearCacheTimer;
|
||||||
|
|
||||||
protected BaseNetworkManager(ILogger logger)
|
protected BaseNetworkManager(ILogger logger)
|
||||||
{
|
{
|
||||||
Logger = 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;
|
private volatile List<string> _localIpAddresses;
|
||||||
@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
var addresses = GetLocalIpAddressesInternal().ToList();
|
var addresses = GetLocalIpAddressesInternal().ToList();
|
||||||
|
|
||||||
_localIpAddresses = addresses;
|
_localIpAddresses = addresses;
|
||||||
BindEvents();
|
|
||||||
|
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||||||
return _localIpAddresses;
|
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()
|
private IEnumerable<string> GetLocalIpAddressesInternal()
|
||||||
{
|
{
|
||||||
var list = GetIPsDefault()
|
var list = GetIPsDefault()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="NLog" version="3.2.0.0" targetFramework="net45" />
|
<package id="NLog" version="3.2.1" targetFramework="net45" />
|
||||||
<package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
|
<package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
|
9
MediaBrowser.Controller/Dlna/ISsdpHandler.cs
Normal file
9
MediaBrowser.Controller/Dlna/ISsdpHandler.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Dlna
|
||||||
|
{
|
||||||
|
public interface ISsdpHandler
|
||||||
|
{
|
||||||
|
event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Ssdp
|
namespace MediaBrowser.Controller.Dlna
|
||||||
{
|
{
|
||||||
public class SsdpMessageEventArgs
|
public class SsdpMessageEventArgs
|
||||||
{
|
{
|
||||||
@ -13,6 +13,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
public Dictionary<string, string> Headers { get; set; }
|
public Dictionary<string, string> Headers { get; set; }
|
||||||
|
|
||||||
public IPAddress LocalIp { get; set; }
|
public IPAddress LocalIp { get; set; }
|
||||||
|
public byte[] Message { get; set; }
|
||||||
|
|
||||||
public SsdpMessageEventArgs()
|
public SsdpMessageEventArgs()
|
||||||
{
|
{
|
@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
||||||
public bool HasEmbeddedImage { get; set; }
|
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]
|
[IgnoreDataMember]
|
||||||
protected override bool SupportsOwnedItems
|
protected override bool SupportsOwnedItems
|
||||||
{
|
{
|
||||||
@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Parents.OfType<MusicAlbum>().FirstOrDefault();
|
return AlbumEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// <value>The album.</value>
|
/// <value>The album.</value>
|
||||||
public string Album { get; set; }
|
public string Album { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public MusicAlbum AlbumEntity
|
||||||
|
{
|
||||||
|
get { return FindParent<MusicAlbum>(); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the media.
|
/// Gets the type of the media.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected override string CreateUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
var parent = FindParent<MusicAlbum>();
|
var parent = AlbumEntity;
|
||||||
|
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
||||||
{
|
{
|
||||||
public List<Guid> SoundtrackIds { get; set; }
|
|
||||||
|
|
||||||
public MusicAlbum()
|
public MusicAlbum()
|
||||||
{
|
{
|
||||||
SoundtrackIds = new List<Guid>();
|
|
||||||
Artists = new List<string>();
|
Artists = new List<string>();
|
||||||
AlbumArtists = new List<string>();
|
AlbumArtists = new List<string>();
|
||||||
}
|
}
|
||||||
@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||||||
return Tracks;
|
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; }
|
public List<string> Artists { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
/// <value>The provider ids.</value>
|
/// <value>The provider ids.</value>
|
||||||
public Dictionary<string, string> ProviderIds { get; set; }
|
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]
|
[IgnoreDataMember]
|
||||||
public virtual Folder LatestItemsIndexContainer
|
public virtual Folder LatestItemsIndexContainer
|
||||||
{
|
{
|
||||||
|
@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
/// <value>The index number.</value>
|
/// <value>The index number.</value>
|
||||||
public int? IndexNumberEnd { get; set; }
|
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]
|
[IgnoreDataMember]
|
||||||
protected override bool SupportsOwnedItems
|
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]
|
[IgnoreDataMember]
|
||||||
public override Folder LatestItemsIndexContainer
|
public override Folder LatestItemsIndexContainer
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using MediaBrowser.Controller.Localization;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Providers;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
|
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]
|
[IgnoreDataMember]
|
||||||
public override bool SupportsAddingToPlaylist
|
public override bool SupportsAddingToPlaylist
|
||||||
{
|
{
|
||||||
@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
get { return Series ?? Parent; }
|
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
|
// Genre, Rating and Stuido will all be the same
|
||||||
protected override IEnumerable<string> GetIndexByOptions()
|
protected override IEnumerable<string> GetIndexByOptions()
|
||||||
{
|
{
|
||||||
|
@ -94,19 +94,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Series aren't included directly in indices - Their Episodes will roll up to them
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool IncludeInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -283,5 +283,17 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
return hour >= schedule.StartHour && hour <= schedule.EndHour;
|
return hour >= schedule.StartHour && hour <= schedule.EndHour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsFolderGrouped(Guid id)
|
||||||
|
{
|
||||||
|
var config = Configuration;
|
||||||
|
|
||||||
|
if (config.ExcludeFoldersFromGrouping != null)
|
||||||
|
{
|
||||||
|
return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1754,12 +1754,10 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
|
|
||||||
private IEnumerable<Folder> GetMediaFolders(User user)
|
private IEnumerable<Folder> GetMediaFolders(User user)
|
||||||
{
|
{
|
||||||
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
|
|
||||||
|
|
||||||
return user.RootFolder
|
return user.RootFolder
|
||||||
.GetChildren(user, true, true)
|
.GetChildren(user, true, true)
|
||||||
.OfType<Folder>()
|
.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)
|
private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
|
||||||
|
@ -116,7 +116,9 @@
|
|||||||
<Compile Include="Dlna\IDlnaManager.cs" />
|
<Compile Include="Dlna\IDlnaManager.cs" />
|
||||||
<Compile Include="Dlna\IEventManager.cs" />
|
<Compile Include="Dlna\IEventManager.cs" />
|
||||||
<Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
|
<Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
|
||||||
|
<Compile Include="Dlna\ISsdpHandler.cs" />
|
||||||
<Compile Include="Dlna\IUpnpService.cs" />
|
<Compile Include="Dlna\IUpnpService.cs" />
|
||||||
|
<Compile Include="Dlna\SsdpMessageEventArgs.cs" />
|
||||||
<Compile Include="Drawing\IImageProcessor.cs" />
|
<Compile Include="Drawing\IImageProcessor.cs" />
|
||||||
<Compile Include="Drawing\ImageCollageOptions.cs" />
|
<Compile Include="Drawing\ImageCollageOptions.cs" />
|
||||||
<Compile Include="Drawing\ImageProcessingOptions.cs" />
|
<Compile Include="Drawing\ImageProcessingOptions.cs" />
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Dlna.ContentDirectory;
|
using MediaBrowser.Dlna.ContentDirectory;
|
||||||
using MediaBrowser.Dlna.PlayTo;
|
using MediaBrowser.Dlna.PlayTo;
|
||||||
|
@ -149,8 +149,6 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
targetHeight,
|
targetHeight,
|
||||||
streamInfo.TargetVideoBitDepth,
|
streamInfo.TargetVideoBitDepth,
|
||||||
streamInfo.TargetVideoBitrate,
|
streamInfo.TargetVideoBitrate,
|
||||||
streamInfo.TargetAudioChannels,
|
|
||||||
streamInfo.TargetAudioBitrate,
|
|
||||||
streamInfo.TargetTimestamp,
|
streamInfo.TargetTimestamp,
|
||||||
streamInfo.IsDirectStream,
|
streamInfo.IsDirectStream,
|
||||||
streamInfo.RunTimeTicks,
|
streamInfo.RunTimeTicks,
|
||||||
@ -276,11 +274,9 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec,
|
||||||
streamInfo.VideoCodec,
|
streamInfo.VideoCodec,
|
||||||
streamInfo.TargetAudioBitrate,
|
streamInfo.TargetAudioBitrate,
|
||||||
targetChannels,
|
|
||||||
targetWidth,
|
targetWidth,
|
||||||
targetHeight,
|
targetHeight,
|
||||||
streamInfo.TargetVideoBitDepth,
|
streamInfo.TargetVideoBitDepth,
|
||||||
streamInfo.TargetVideoBitrate,
|
|
||||||
streamInfo.TargetVideoProfile,
|
streamInfo.TargetVideoProfile,
|
||||||
streamInfo.TargetVideoLevel,
|
streamInfo.TargetVideoLevel,
|
||||||
streamInfo.TargetFramerate,
|
streamInfo.TargetFramerate,
|
||||||
|
@ -482,7 +482,7 @@ namespace MediaBrowser.Dlna
|
|||||||
var profile = GetProfile(headers) ??
|
var profile = GetProfile(headers) ??
|
||||||
GetDefaultProfile();
|
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)
|
public ImageStream GetIcon(string filename)
|
||||||
@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
|
|||||||
new DirectTvProfile(),
|
new DirectTvProfile(),
|
||||||
new DishHopperJoeyProfile(),
|
new DishHopperJoeyProfile(),
|
||||||
new DefaultProfile(),
|
new DefaultProfile(),
|
||||||
new PopcornHourProfile()
|
new PopcornHourProfile(),
|
||||||
|
new VlcProfile(),
|
||||||
|
new BubbleUpnpProfile()
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var item in list)
|
foreach (var item in list)
|
||||||
|
@ -37,13 +37,26 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
|
|
||||||
private SsdpHandler _ssdpHandler;
|
private readonly SsdpHandler _ssdpHandler;
|
||||||
private DeviceDiscovery _deviceDiscovery;
|
private DeviceDiscovery _deviceDiscovery;
|
||||||
|
|
||||||
private readonly List<string> _registeredServerIds = new List<string>();
|
private readonly List<string> _registeredServerIds = new List<string>();
|
||||||
private bool _dlnaServerStarted;
|
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;
|
_config = config;
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
@ -57,6 +70,7 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
|
_ssdpHandler = (SsdpHandler)ssdpHandler;
|
||||||
_logger = logManager.GetLogger("Dlna");
|
_logger = logManager.GetLogger("Dlna");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +123,6 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ssdpHandler = new SsdpHandler(_logger, _config, GenerateServerSignature());
|
|
||||||
|
|
||||||
_ssdpHandler.Start();
|
_ssdpHandler.Start();
|
||||||
|
|
||||||
_deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
|
_deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
|
||||||
@ -123,7 +135,7 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeSsdpHandler()
|
private void DisposeDeviceDiscovery()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -133,15 +145,6 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
{
|
{
|
||||||
_logger.ErrorException("Error disposing device discovery", ex);
|
_logger.ErrorException("Error disposing device discovery", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ssdpHandler.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing ssdp handler", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartDlnaServer()
|
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 readonly object _syncLock = new object();
|
||||||
private void StartPlayToManager()
|
private void StartPlayToManager()
|
||||||
{
|
{
|
||||||
@ -260,7 +240,7 @@ namespace MediaBrowser.Dlna.Main
|
|||||||
{
|
{
|
||||||
DisposeDlnaServer();
|
DisposeDlnaServer();
|
||||||
DisposePlayToManager();
|
DisposePlayToManager();
|
||||||
DisposeSsdpHandler();
|
DisposeDeviceDiscovery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisposeDlnaServer()
|
public void DisposeDlnaServer()
|
||||||
|
@ -77,10 +77,12 @@
|
|||||||
<Compile Include="Common\DeviceService.cs" />
|
<Compile Include="Common\DeviceService.cs" />
|
||||||
<Compile Include="Didl\DidlBuilder.cs" />
|
<Compile Include="Didl\DidlBuilder.cs" />
|
||||||
<Compile Include="PlayTo\PlayToController.cs" />
|
<Compile Include="PlayTo\PlayToController.cs" />
|
||||||
|
<Compile Include="Profiles\BubbleUpnpProfile.cs" />
|
||||||
<Compile Include="Profiles\DefaultProfile.cs" />
|
<Compile Include="Profiles\DefaultProfile.cs" />
|
||||||
<Compile Include="Profiles\DirectTvProfile.cs" />
|
<Compile Include="Profiles\DirectTvProfile.cs" />
|
||||||
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
||||||
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
||||||
|
<Compile Include="Profiles\VlcProfile.cs" />
|
||||||
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
||||||
<Compile Include="Ssdp\Extensions.cs" />
|
<Compile Include="Ssdp\Extensions.cs" />
|
||||||
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
||||||
@ -135,7 +137,6 @@
|
|||||||
<Compile Include="Server\Headers.cs" />
|
<Compile Include="Server\Headers.cs" />
|
||||||
<Compile Include="Server\UpnpDevice.cs" />
|
<Compile Include="Server\UpnpDevice.cs" />
|
||||||
<Compile Include="Ssdp\SsdpMessageBuilder.cs" />
|
<Compile Include="Ssdp\SsdpMessageBuilder.cs" />
|
||||||
<Compile Include="Ssdp\SsdpMessageEventArgs.cs" />
|
|
||||||
<Compile Include="Ssdp\SsdpHandler.cs" />
|
<Compile Include="Ssdp\SsdpHandler.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -205,6 +206,10 @@
|
|||||||
<EmbeddedResource Include="Images\people480.jpg" />
|
<EmbeddedResource Include="Images\people480.jpg" />
|
||||||
<EmbeddedResource Include="Images\people480.png" />
|
<EmbeddedResource Include="Images\people480.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
|
||||||
|
<EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- 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.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
}
|
}
|
||||||
|
|
||||||
var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
|
|
||||||
if (service == null)
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
|
|
||||||
if (service == null)
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
if (service == null)
|
if (service == null)
|
||||||
return 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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
throw new InvalidOperationException("Unable to find service");
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
throw new InvalidOperationException("Unable to find service");
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
@ -509,8 +509,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
streamInfo.TargetHeight,
|
streamInfo.TargetHeight,
|
||||||
streamInfo.TargetVideoBitDepth,
|
streamInfo.TargetVideoBitDepth,
|
||||||
streamInfo.TargetVideoBitrate,
|
streamInfo.TargetVideoBitrate,
|
||||||
streamInfo.TargetAudioChannels,
|
|
||||||
streamInfo.TargetAudioBitrate,
|
|
||||||
streamInfo.TargetTimestamp,
|
streamInfo.TargetTimestamp,
|
||||||
streamInfo.IsDirectStream,
|
streamInfo.IsDirectStream,
|
||||||
streamInfo.RunTimeTicks,
|
streamInfo.RunTimeTicks,
|
||||||
@ -770,8 +768,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
|
|
||||||
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
|
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);
|
await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
@ -34,6 +35,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
private readonly DeviceDiscovery _deviceDiscovery;
|
private readonly DeviceDiscovery _deviceDiscovery;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
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)
|
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;
|
_logger = logger;
|
||||||
@ -53,9 +57,19 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
_clearNonRenderersTimer = new Timer(OnClearUrlTimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
|
||||||
|
|
||||||
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
|
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnClearUrlTimerCallback(object state)
|
||||||
|
{
|
||||||
|
lock (_nonRendererUrls)
|
||||||
|
{
|
||||||
|
_nonRendererUrls.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
|
async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
|
||||||
{
|
{
|
||||||
var localIp = e.LocalIp;
|
var localIp = e.LocalIp;
|
||||||
@ -68,7 +82,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
|
|
||||||
string location;
|
string location;
|
||||||
if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
|
if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
|
||||||
|
|
||||||
// It has to report that it's a media renderer
|
// It has to report that it's a media renderer
|
||||||
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
|
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
|
||||||
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
|
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
|
||||||
@ -85,62 +99,75 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
var uri = new Uri(location);
|
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);
|
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)
|
lock (_nonRendererUrls)
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
var controller = sessionInfo.SessionController as PlayToController;
|
|
||||||
|
|
||||||
if (controller == null)
|
|
||||||
{
|
{
|
||||||
var serverAddress = GetServerAddress(localIp);
|
_nonRendererUrls.Add(location);
|
||||||
string accessToken = null;
|
return;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -156,6 +183,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
|
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
|
||||||
|
|
||||||
|
if (_clearNonRenderersTimer != null)
|
||||||
|
{
|
||||||
|
_clearNonRenderersTimer.Dispose();
|
||||||
|
_clearNonRenderersTimer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Dlna.Common;
|
using MediaBrowser.Dlna.Common;
|
||||||
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
public class SsdpHttpClient
|
public class SsdpHttpClient
|
||||||
{
|
{
|
||||||
private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
|
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 IHttpClient _httpClient;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
DeviceService service,
|
DeviceService service,
|
||||||
string command,
|
string command,
|
||||||
string postData,
|
string postData,
|
||||||
|
bool logRequest = true,
|
||||||
string header = null)
|
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);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
using (var stream = response.Content)
|
using (var stream = response.Content)
|
||||||
@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
||||||
string soapAction,
|
string soapAction,
|
||||||
string postData,
|
string postData,
|
||||||
string header = null)
|
string header,
|
||||||
|
bool logRequest)
|
||||||
{
|
{
|
||||||
if (!soapAction.StartsWith("\""))
|
if (!soapAction.StartsWith("\""))
|
||||||
soapAction = "\"" + soapAction + "\"";
|
soapAction = "\"" + soapAction + "\"";
|
||||||
@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System.Xml.Serialization;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
|
{
|
||||||
|
[XmlRoot("Profile")]
|
||||||
|
public class BubbleUpnpProfile : DefaultProfile
|
||||||
|
{
|
||||||
|
public BubbleUpnpProfile()
|
||||||
|
{
|
||||||
|
Name = "BubbleUPnp";
|
||||||
|
|
||||||
|
TimelineOffsetSeconds = 5;
|
||||||
|
|
||||||
|
Identification = new DeviceIdentification
|
||||||
|
{
|
||||||
|
ModelName = "BubbleUPnp",
|
||||||
|
|
||||||
|
Headers = new[]
|
||||||
|
{
|
||||||
|
new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TranscodingProfiles = new[]
|
||||||
|
{
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "mp3",
|
||||||
|
Type = DlnaProfileType.Audio,
|
||||||
|
AudioCodec = "mp3"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "ts",
|
||||||
|
Type = DlnaProfileType.Video,
|
||||||
|
VideoCodec = "h264",
|
||||||
|
AudioCodec = "aac"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "jpeg",
|
||||||
|
Type = DlnaProfileType.Photo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectPlayProfiles = new[]
|
||||||
|
{
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||||
|
Type = DlnaProfileType.Video
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "mp3,flac,asf,off,oga,aac",
|
||||||
|
Type = DlnaProfileType.Audio
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Type = DlnaProfileType.Photo,
|
||||||
|
|
||||||
|
Container = "jpeg,png,gif,bmp,tiff"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResponseProfiles = new ResponseProfile[] { };
|
||||||
|
|
||||||
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
|
|
||||||
|
CodecProfiles = new CodecProfile[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Profiles
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
@ -75,6 +76,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
|
||||||
|
AddXmlRootAttribute("xmlns:dlna", "urn:schemas-dlna-org:device-1-0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddXmlRootAttribute(string name, string value)
|
||||||
|
{
|
||||||
|
var atts = XmlRootAttributes ?? new XmlAttribute[] { };
|
||||||
|
var list = atts.ToList();
|
||||||
|
|
||||||
|
list.Add(new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Value = value
|
||||||
|
});
|
||||||
|
|
||||||
|
XmlRootAttributes = list.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:pv",
|
|
||||||
Value = "http://www.pv.com/pvns/"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TimelineOffsetSeconds = 10;
|
TimelineOffsetSeconds = 10;
|
||||||
|
|
||||||
|
@ -27,14 +27,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:sec",
|
|
||||||
Value = "http://www.sec.co.kr/"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -17,14 +17,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ModelNumber = "BDP-2013"
|
ModelNumber = "BDP-2013"
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
|
@ -33,14 +33,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AlbumArtPn = "JPEG_TN";
|
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";
|
"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;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
@ -293,6 +287,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AlbumArtPn = "JPEG_TN";
|
AlbumArtPn = "JPEG_TN";
|
||||||
|
|
||||||
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
@ -310,6 +304,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AlbumArtPn = "JPEG_TN";
|
AlbumArtPn = "JPEG_TN";
|
||||||
|
|
||||||
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
@ -250,6 +244,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlRootAttributes = new[]
|
AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
|
||||||
{
|
|
||||||
new XmlAttribute
|
|
||||||
{
|
|
||||||
Name = "xmlns:av",
|
|
||||||
Value = "urn:schemas-sony-com:av"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AlbumArtPn = "JPEG_TN";
|
AlbumArtPn = "JPEG_TN";
|
||||||
|
|
||||||
@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
@ -284,6 +278,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System.Xml.Serialization;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
|
{
|
||||||
|
[XmlRoot("Profile")]
|
||||||
|
public class VlcProfile : DefaultProfile
|
||||||
|
{
|
||||||
|
public VlcProfile()
|
||||||
|
{
|
||||||
|
Name = "Vlc";
|
||||||
|
|
||||||
|
TimelineOffsetSeconds = 5;
|
||||||
|
|
||||||
|
Identification = new DeviceIdentification
|
||||||
|
{
|
||||||
|
ModelName = "Vlc",
|
||||||
|
|
||||||
|
Headers = new[]
|
||||||
|
{
|
||||||
|
new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TranscodingProfiles = new[]
|
||||||
|
{
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "mp3",
|
||||||
|
Type = DlnaProfileType.Audio,
|
||||||
|
AudioCodec = "mp3"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "ts",
|
||||||
|
Type = DlnaProfileType.Video,
|
||||||
|
VideoCodec = "h264",
|
||||||
|
AudioCodec = "aac"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "jpeg",
|
||||||
|
Type = DlnaProfileType.Photo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectPlayProfiles = new[]
|
||||||
|
{
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||||
|
Type = DlnaProfileType.Video
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "mp3,flac,asf,off,oga,aac",
|
||||||
|
Type = DlnaProfileType.Audio
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Type = DlnaProfileType.Photo,
|
||||||
|
|
||||||
|
Container = "jpeg,png,gif,bmp,tiff"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResponseProfiles = new ResponseProfile[] { };
|
||||||
|
|
||||||
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
|
|
||||||
|
CodecProfiles = new CodecProfile[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
Name = "WDTV Live";
|
Name = "WDTV Live";
|
||||||
|
|
||||||
TimelineOffsetSeconds = 5;
|
TimelineOffsetSeconds = 5;
|
||||||
IgnoreTranscodeByteRangeRequests = true;
|
|
||||||
|
|
||||||
Identification = new DeviceIdentification
|
Identification = new DeviceIdentification
|
||||||
{
|
{
|
||||||
|
@ -18,12 +18,13 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
|
|
||||||
ModelNumber = "12.0";
|
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";
|
Manufacturer = "Microsoft Corporation";
|
||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com";
|
||||||
XDlnaDoc = "DMS-1.50";
|
XDlnaDoc = "DMS-1.50";
|
||||||
|
ModelDescription = null;
|
||||||
|
|
||||||
TimelineOffsetSeconds = 40;
|
TimelineOffsetSeconds = 40;
|
||||||
RequiresPlainFolders = true;
|
RequiresPlainFolders = true;
|
||||||
@ -311,6 +312,9 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
XmlRootAttributes = new XmlAttribute[] { };
|
||||||
|
AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
|
|
||||||
Identification = new DeviceIdentification
|
Identification = new DeviceIdentification
|
||||||
{
|
{
|
||||||
FriendlyName = "XboxOne",
|
ModelName = "Xbox One",
|
||||||
|
|
||||||
Headers = new[]
|
Headers = new[]
|
||||||
{
|
{
|
||||||
|
53
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
53
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
File diff suppressed because one or more lines are too long
@ -8,7 +8,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -27,7 +26,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4" type="Video" />
|
<DirectPlayProfile container="avi,mp4" type="Video" />
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -32,7 +31,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||||
</DirectPlayProfiles>
|
</DirectPlayProfiles>
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -33,7 +32,10 @@
|
|||||||
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>true</RequiresPlainFolders>
|
<RequiresPlainFolders>true</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
|
<DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
|
||||||
<DirectPlayProfile container="jpeg,jpg" type="Photo" />
|
<DirectPlayProfile container="jpeg,jpg" type="Photo" />
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,7 +33,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp4,mkv,mpeg,ts" audioCodec="mp3,ac3,aac,he-aac,pcm" videoCodec="h264,mpeg2video" type="Video" />
|
<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" />
|
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
|
||||||
|
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
File diff suppressed because one or more lines are too long
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -33,7 +32,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -31,7 +30,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
|
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||||
@ -33,7 +32,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
||||||
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -35,6 +34,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
|
<XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -27,7 +26,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp4,mov" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
|
<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" />
|
<DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,6 +33,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
|
<XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,6 +33,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -36,6 +35,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
@ -36,6 +35,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
@ -79,6 +80,7 @@
|
|||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
@ -36,6 +35,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
@ -82,6 +83,7 @@
|
|||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
@ -36,6 +35,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
@ -67,6 +68,7 @@
|
|||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
@ -36,6 +35,8 @@
|
|||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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" />
|
||||||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
</XmlRootAttributes>
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
@ -72,6 +73,7 @@
|
|||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -35,7 +34,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||||
|
53
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
53
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
File diff suppressed because one or more lines are too long
@ -15,7 +15,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,7 +33,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
<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" />
|
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||||
|
@ -8,14 +8,12 @@
|
|||||||
<HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
|
<HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
|
||||||
</Headers>
|
</Headers>
|
||||||
</Identification>
|
</Identification>
|
||||||
<FriendlyName>${HostName} : 1</FriendlyName>
|
<FriendlyName>${HostName}: Emby:</FriendlyName>
|
||||||
<Manufacturer>Microsoft Corporation</Manufacturer>
|
<Manufacturer>Microsoft Corporation</Manufacturer>
|
||||||
<ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
|
<ManufacturerUrl>http://www.microsoft.com</ManufacturerUrl>
|
||||||
<ModelName>Windows Media Player Sharing</ModelName>
|
<ModelName>Windows Media Player Sharing</ModelName>
|
||||||
<ModelDescription>Emby</ModelDescription>
|
|
||||||
<ModelNumber>12.0</ModelNumber>
|
<ModelNumber>12.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://go.microsoft.com/fwlink/?LinkId=105926</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,7 +32,9 @@
|
|||||||
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>true</RequiresPlainFolders>
|
<RequiresPlainFolders>true</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
|
<EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
|
||||||
<XmlRootAttributes />
|
<XmlRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
|
||||||
|
</XmlRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||||
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
<Name>Xbox One</Name>
|
<Name>Xbox One</Name>
|
||||||
<Identification>
|
<Identification>
|
||||||
<FriendlyName>XboxOne</FriendlyName>
|
<ModelName>Xbox One</ModelName>
|
||||||
<Headers>
|
<Headers>
|
||||||
<HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
|
<HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
|
||||||
<HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
|
<HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
|
||||||
@ -15,7 +15,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
@ -34,7 +33,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||||
@ -33,7 +32,10 @@
|
|||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
<EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
|
<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>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
|
||||||
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
|
||||||
|
@ -18,8 +18,9 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
private readonly string _serverUdn;
|
private readonly string _serverUdn;
|
||||||
private readonly string _serverAddress;
|
private readonly string _serverAddress;
|
||||||
private readonly string _serverName;
|
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))
|
if (string.IsNullOrWhiteSpace(serverUdn))
|
||||||
{
|
{
|
||||||
@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
_serverUdn = serverUdn;
|
_serverUdn = serverUdn;
|
||||||
_serverAddress = serverAddress;
|
_serverAddress = serverAddress;
|
||||||
_serverName = serverName;
|
_serverName = serverName;
|
||||||
|
_serverId = serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool EnableAbsoluteUrls
|
private bool EnableAbsoluteUrls
|
||||||
@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
|
|
||||||
builder.Append("<?xml version=\"1.0\"?>");
|
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)
|
foreach (var att in _profile.XmlRootAttributes)
|
||||||
{
|
{
|
||||||
builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
|
builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
|
||||||
@ -72,7 +74,7 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
builder.Append("<device>");
|
builder.Append("<device>");
|
||||||
AppendDeviceProperties(builder);
|
AppendDeviceProperties(builder);
|
||||||
|
|
||||||
AppendIconList(builder);
|
//AppendIconList(builder);
|
||||||
AppendServiceList(builder);
|
AppendServiceList(builder);
|
||||||
builder.Append("</device>");
|
builder.Append("</device>");
|
||||||
}
|
}
|
||||||
@ -80,20 +82,37 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
private void AppendDeviceProperties(StringBuilder builder)
|
private void AppendDeviceProperties(StringBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Append("<UDN>uuid:" + SecurityElement.Escape(_serverUdn) + "</UDN>");
|
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\">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("<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("<friendlyName>" + SecurityElement.Escape(GetFriendlyName()) + "</friendlyName>");
|
||||||
builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
|
builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
|
||||||
builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
|
builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
|
||||||
builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
|
builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
|
||||||
builder.Append("<modelName>" + SecurityElement.Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
|
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("<modelNumber>" + SecurityElement.Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
|
||||||
builder.Append("<modelURL>" + SecurityElement.Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
|
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>");
|
builder.Append("<presentationURL>" + SecurityElement.Escape(_serverAddress) + "</presentationURL>");
|
||||||
|
|
||||||
|
@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
LogRequest(request);
|
LogRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = ProcessControlRequestInternal(request);
|
var response = ProcessControlRequestInternal(request);
|
||||||
|
|
||||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
LogResponse(response);
|
LogResponse(response);
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
public EndPoint FromEndPoint { get; private set; }
|
public EndPoint FromEndPoint { get; private set; }
|
||||||
public string Message { get; private set; }
|
public string Message { get; private set; }
|
||||||
public bool IgnoreBindFailure { get; private set; }
|
public bool IgnoreBindFailure { get; private set; }
|
||||||
|
public bool EnableDebugLogging { get; private set; }
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
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;
|
Message = message;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
EnableDebugLogging = enableDebugLogging;
|
||||||
IgnoreBindFailure = ignoreBindFailure;
|
IgnoreBindFailure = ignoreBindFailure;
|
||||||
FromEndPoint = fromEndPoint;
|
FromEndPoint = fromEndPoint;
|
||||||
ToEndPoint = toEndPoint;
|
ToEndPoint = toEndPoint;
|
||||||
@ -27,59 +29,93 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
public void Send()
|
public void Send()
|
||||||
{
|
{
|
||||||
var msg = Encoding.ASCII.GetBytes(Message);
|
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
|
try
|
||||||
{
|
{
|
||||||
client.EndSend(result);
|
socket.EndSend(result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (!IgnoreBindFailure)
|
if (!IgnoreBindFailure || EnableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
try
|
CloseSocket(socket, true);
|
||||||
{
|
|
||||||
client.Close();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
_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()
|
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);
|
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||||
return socket;
|
return socket;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error creating socket", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -142,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
args.EndPoint = endPoint;
|
args.EndPoint = endPoint;
|
||||||
args.LocalIp = localIp;
|
args.LocalIp = localIp;
|
||||||
|
|
||||||
TryCreateDevice(args);
|
if (!_ssdpHandler.IsSelfNotification(args))
|
||||||
|
{
|
||||||
|
TryCreateDevice(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +186,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
}
|
}
|
||||||
|
|
||||||
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
|
}, _tokenSource.Token, TaskCreationOptions.LongRunning);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
|
private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
|
||||||
@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
string nts;
|
string nts;
|
||||||
args.Headers.TryGetValue("NTS", out 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;
|
string usn;
|
||||||
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
||||||
|
|
||||||
string nt;
|
string nt;
|
||||||
if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
|
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
|
// Need to be able to download device description
|
||||||
string location;
|
string location;
|
||||||
if (!args.Headers.TryGetValue("Location", out location) ||
|
if (!args.Headers.TryGetValue("Location", out location) ||
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common;
|
||||||
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Dlna.Server;
|
using MediaBrowser.Dlna.Server;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
@ -16,7 +18,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace MediaBrowser.Dlna.Ssdp
|
namespace MediaBrowser.Dlna.Ssdp
|
||||||
{
|
{
|
||||||
public class SsdpHandler : IDisposable
|
public class SsdpHandler : IDisposable, ISsdpHandler
|
||||||
{
|
{
|
||||||
private Socket _socket;
|
private Socket _socket;
|
||||||
|
|
||||||
@ -39,13 +41,39 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
|
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;
|
_logger = logger;
|
||||||
_config = config;
|
_config = config;
|
||||||
_serverSignature = serverSignature;
|
_appHost = appHost;
|
||||||
|
|
||||||
_config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
|
_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)
|
void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
|
||||||
@ -60,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
|
|
||||||
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
||||||
{
|
{
|
||||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
|
var headers = args.Headers;
|
||||||
{
|
string st;
|
||||||
var headers = args.Headers;
|
|
||||||
|
|
||||||
|
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
|
||||||
|
{
|
||||||
TimeSpan delay = GetSearchDelay(headers);
|
TimeSpan delay = GetSearchDelay(headers);
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(delay).ConfigureAwait(false);
|
await Task.Delay(delay).ConfigureAwait(false);
|
||||||
|
|
||||||
string st;
|
RespondToSearch(args.EndPoint, st);
|
||||||
if (headers.TryGetValue("st", out st))
|
|
||||||
{
|
|
||||||
RespondToSearch(args.EndPoint, st);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
||||||
@ -117,7 +142,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
values["MX"] = "3";
|
values["MX"] = "3";
|
||||||
|
|
||||||
// UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
|
// 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,
|
public void SendDatagram(string header,
|
||||||
@ -138,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||||
var queued = false;
|
var queued = false;
|
||||||
|
|
||||||
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
for (var i = 0; i < sendCount; i++)
|
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)
|
if (_messageQueue.Count == 0)
|
||||||
{
|
{
|
||||||
@ -184,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
|
|
||||||
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
||||||
{
|
{
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
{
|
|
||||||
_logger.Debug("RespondToSearch");
|
var isLogged = false;
|
||||||
}
|
|
||||||
|
|
||||||
const string header = "HTTP/1.1 200 OK";
|
const string header = "HTTP/1.1 200 OK";
|
||||||
|
|
||||||
@ -196,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(deviceType, d.Type, 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);
|
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
values["CACHE-CONTROL"] = "max-age = 600";
|
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, new IPEndPoint(d.Address, 0), true, 1);
|
||||||
//SendDatagram(header, values, endpoint, null, true);
|
//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());
|
_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;
|
var received = (byte[])result.AsyncState;
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug(Encoding.ASCII.GetString(received));
|
_logger.Debug(Encoding.ASCII.GetString(received));
|
||||||
}
|
}
|
||||||
@ -296,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
var args = SsdpHelper.ParseSsdpResponse(received);
|
var args = SsdpHelper.ParseSsdpResponse(received);
|
||||||
args.EndPoint = endpoint;
|
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 headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||||
var headerText = string.Join(",", headerTexts.ToArray());
|
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
||||||
@ -371,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
|
|
||||||
private void NotifyAll()
|
private void NotifyAll()
|
||||||
{
|
{
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug("Sending alive notifications");
|
_logger.Debug("Sending alive notifications");
|
||||||
}
|
}
|
||||||
foreach (var d in RegisteredDevices)
|
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";
|
const string header = "NOTIFY * HTTP/1.1";
|
||||||
|
|
||||||
@ -396,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
values["NT"] = dev.Type;
|
values["NT"] = dev.Type;
|
||||||
values["USN"] = dev.USN;
|
values["USN"] = dev.USN;
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (logMessage)
|
||||||
{
|
{
|
||||||
_logger.Debug("{0} said {1}", dev.USN, type);
|
_logger.Debug("{0} said {1}", dev.USN, type);
|
||||||
}
|
}
|
||||||
@ -429,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
|
|
||||||
foreach (var d in dl.ToList())
|
foreach (var d in dl.ToList())
|
||||||
{
|
{
|
||||||
NotifyDevice(d, "byebye", 2);
|
NotifyDevice(d, "byebye", 2, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Unregistered mount {0}", uuid);
|
_logger.Debug("Unregistered mount {0}", uuid);
|
||||||
@ -440,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
private int _aliveNotifierIntervalMs;
|
private int _aliveNotifierIntervalMs;
|
||||||
private void ReloadAliveNotifier()
|
private void ReloadAliveNotifier()
|
||||||
{
|
{
|
||||||
if (!_config.GetDlnaConfiguration().BlastAliveMessages)
|
var config = _config.GetDlnaConfiguration();
|
||||||
|
|
||||||
|
if (!config.BlastAliveMessages)
|
||||||
{
|
{
|
||||||
DisposeNotificationTimer();
|
DisposeNotificationTimer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
|
var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
|
||||||
|
|
||||||
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -34,7 +35,8 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||||||
return new SsdpMessageEventArgs
|
return new SsdpMessageEventArgs
|
||||||
{
|
{
|
||||||
Method = method,
|
Method = method,
|
||||||
Headers = headers
|
Headers = headers,
|
||||||
|
Message = data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
var maxHeightParam = request.MaxHeight.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
|
// If a fixed width was requested
|
||||||
@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If a max width was requested
|
// 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);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
|
|
||||||
@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If a max height was requested
|
// 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);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
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;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||||
|
@ -716,8 +716,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
profile.GetVideoMediaProfile(outputContainer,
|
profile.GetVideoMediaProfile(outputContainer,
|
||||||
audioCodec,
|
audioCodec,
|
||||||
videoCodec,
|
videoCodec,
|
||||||
state.OutputAudioBitrate,
|
|
||||||
state.OutputAudioChannels,
|
|
||||||
state.OutputWidth,
|
state.OutputWidth,
|
||||||
state.OutputHeight,
|
state.OutputHeight,
|
||||||
state.TargetVideoBitDepth,
|
state.TargetVideoBitDepth,
|
||||||
|
@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
|
|
||||||
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
try
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (result.streams != null)
|
StartProcess(processWrapper);
|
||||||
{
|
|
||||||
// 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 (Exception ex)
|
||||||
catch
|
{
|
||||||
{
|
_ffProbeResourcePool.Release();
|
||||||
StopProcess(processWrapper, 100, true);
|
|
||||||
|
|
||||||
throw;
|
_logger.ErrorException("Error starting ffprobe", ex);
|
||||||
}
|
|
||||||
finally
|
throw;
|
||||||
{
|
}
|
||||||
_ffProbeResourcePool.Release();
|
|
||||||
|
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));
|
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);
|
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
StartProcess(processWrapper);
|
|
||||||
|
|
||||||
var lines = new List<int>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
process.BeginErrorReadLine();
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
var lines = new List<int>();
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
try
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
throw;
|
process.BeginErrorReadLine();
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
StopProcess(processWrapper, 100, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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);
|
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
bool ranToCompletion;
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
bool ranToCompletion;
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
#pragma warning disable 4014
|
#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
|
// 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);
|
process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
|
||||||
#pragma warning restore 4014
|
#pragma warning restore 4014
|
||||||
|
|
||||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||||
process.BeginErrorReadLine();
|
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)
|
public string GetTimeParameter(long ticks)
|
||||||
@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
|
|
||||||
bool ranToCompletion = false;
|
bool ranToCompletion = false;
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
try
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
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;
|
if (process.WaitForExit(30000))
|
||||||
break;
|
{
|
||||||
|
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();
|
if (!ranToCompletion)
|
||||||
|
{
|
||||||
var jpegCount = Directory.GetFiles(targetDirectory)
|
StopProcess(processWrapper, 1000, false);
|
||||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
}
|
||||||
|
|
||||||
isResponsive = (jpegCount > lastCount);
|
|
||||||
lastCount = jpegCount;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
if (!ranToCompletion)
|
|
||||||
{
|
{
|
||||||
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)
|
if (exitCode == -1)
|
||||||
{
|
{
|
||||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
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 readonly Process Process;
|
||||||
public bool HasExited;
|
public bool HasExited;
|
||||||
@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
|
|
||||||
process.Dispose();
|
process.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
private readonly object _syncLock = new object();
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
if (Process != null)
|
||||||
|
{
|
||||||
|
Process.Exited -= Process_Exited;
|
||||||
|
Process.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Channels;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
|
@ -1499,5 +1499,11 @@ namespace MediaBrowser.Model.ApiClient
|
|||||||
/// <param name="itemIds">The item ids.</param>
|
/// <param name="itemIds">The item ids.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
|
Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the supported bitrate.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task<System.Int32>.</returns>
|
||||||
|
Task<int> GetSupportedBitrate(CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
/// different directories and files.
|
/// different directories and files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The file watcher delay.</value>
|
/// <value>The file watcher delay.</value>
|
||||||
public int RealtimeMonitorDelay { get; set; }
|
public int RealtimeLibraryMonitorDelay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
||||||
@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
// 5 minutes
|
// 5 minutes
|
||||||
MinResumeDurationSeconds = 300;
|
MinResumeDurationSeconds = 300;
|
||||||
|
|
||||||
RealtimeMonitorDelay = 30;
|
RealtimeLibraryMonitorDelay = 40;
|
||||||
|
|
||||||
EnableInternetProviders = true;
|
EnableInternetProviders = true;
|
||||||
FindInternetTrailers = true;
|
FindInternetTrailers = true;
|
||||||
@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
"Chromecast",
|
"Chromecast",
|
||||||
"iOS",
|
"iOS",
|
||||||
"Unknown app",
|
"Unknown app",
|
||||||
"MediaPortal",
|
|
||||||
"Media Portal",
|
|
||||||
"iPad",
|
"iPad",
|
||||||
"iPhone",
|
"iPhone",
|
||||||
"Windows Phone"
|
"Windows Phone"
|
||||||
|
@ -32,6 +32,7 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
public string[] DisplayChannelsWithinViews { get; set; }
|
public string[] DisplayChannelsWithinViews { get; set; }
|
||||||
|
|
||||||
public string[] ExcludeFoldersFromGrouping { get; set; }
|
public string[] ExcludeFoldersFromGrouping { get; set; }
|
||||||
|
public string[] GroupedFolders { get; set; }
|
||||||
|
|
||||||
public SubtitlePlaybackMode SubtitleMode { get; set; }
|
public SubtitlePlaybackMode SubtitleMode { get; set; }
|
||||||
public bool DisplayCollectionsView { get; set; }
|
public bool DisplayCollectionsView { get; set; }
|
||||||
@ -62,12 +63,13 @@ namespace MediaBrowser.Model.Configuration
|
|||||||
OrderedViews = new string[] { };
|
OrderedViews = new string[] { };
|
||||||
DisplayChannelsWithinViews = new string[] { };
|
DisplayChannelsWithinViews = new string[] { };
|
||||||
|
|
||||||
ExcludeFoldersFromGrouping = new string[] { };
|
|
||||||
PlainFolderViews = new string[] { };
|
PlainFolderViews = new string[] { };
|
||||||
DisplayCollectionsView = true;
|
DisplayCollectionsView = true;
|
||||||
|
|
||||||
IncludeTrailersInSuggestions = true;
|
IncludeTrailersInSuggestions = true;
|
||||||
EnableCinemaMode = true;
|
EnableCinemaMode = true;
|
||||||
|
|
||||||
|
GroupedFolders = new string[] { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
[XmlAttribute("codec")]
|
[XmlAttribute("codec")]
|
||||||
public string Codec { get; set; }
|
public string Codec { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("container")]
|
||||||
|
public string Container { get; set; }
|
||||||
|
|
||||||
public CodecProfile()
|
public CodecProfile()
|
||||||
{
|
{
|
||||||
Conditions = new ProfileCondition[] {};
|
Conditions = new ProfileCondition[] {};
|
||||||
@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return list;
|
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();
|
List<string> codecs = GetCodecs();
|
||||||
|
|
||||||
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
||||||
|
@ -7,8 +7,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
public class ConditionProcessor
|
public class ConditionProcessor
|
||||||
{
|
{
|
||||||
public bool IsVideoConditionSatisfied(ProfileCondition condition,
|
public bool IsVideoConditionSatisfied(ProfileCondition condition,
|
||||||
int? audioBitrate,
|
|
||||||
int? audioChannels,
|
|
||||||
int? width,
|
int? width,
|
||||||
int? height,
|
int? height,
|
||||||
int? bitDepth,
|
int? bitDepth,
|
||||||
@ -44,10 +42,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return IsConditionSatisfied(condition, videoProfile);
|
return IsConditionSatisfied(condition, videoProfile);
|
||||||
case ProfileConditionValue.PacketLength:
|
case ProfileConditionValue.PacketLength:
|
||||||
return IsConditionSatisfied(condition, packetLength);
|
return IsConditionSatisfied(condition, packetLength);
|
||||||
case ProfileConditionValue.AudioBitrate:
|
|
||||||
return IsConditionSatisfied(condition, audioBitrate);
|
|
||||||
case ProfileConditionValue.AudioChannels:
|
|
||||||
return IsConditionSatisfied(condition, audioChannels);
|
|
||||||
case ProfileConditionValue.VideoBitDepth:
|
case ProfileConditionValue.VideoBitDepth:
|
||||||
return IsConditionSatisfied(condition, bitDepth);
|
return IsConditionSatisfied(condition, bitDepth);
|
||||||
case ProfileConditionValue.VideoBitrate:
|
case ProfileConditionValue.VideoBitrate:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
@ -105,8 +106,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
int? height,
|
int? height,
|
||||||
int? bitDepth,
|
int? bitDepth,
|
||||||
int? videoBitrate,
|
int? videoBitrate,
|
||||||
int? audioChannels,
|
|
||||||
int? audioBitrate,
|
|
||||||
TransportStreamTimestamp timestamp,
|
TransportStreamTimestamp timestamp,
|
||||||
bool isDirectStream,
|
bool isDirectStream,
|
||||||
long? runtimeTicks,
|
long? runtimeTicks,
|
||||||
@ -147,8 +146,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
|
ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
|
||||||
audioCodec,
|
audioCodec,
|
||||||
videoCodec,
|
videoCodec,
|
||||||
audioBitrate,
|
|
||||||
audioChannels,
|
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
bitDepth,
|
bitDepth,
|
||||||
@ -168,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
||||||
{
|
{
|
||||||
orgPnValues.Add(mediaProfile.OrgPn);
|
orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
public string ModelNumber { get; set; }
|
public string ModelNumber { get; set; }
|
||||||
public string ModelUrl { get; set; }
|
public string ModelUrl { get; set; }
|
||||||
public string SerialNumber { get; set; }
|
public string SerialNumber { get; set; }
|
||||||
public bool IgnoreTranscodeByteRangeRequests { get; set; }
|
|
||||||
|
|
||||||
public bool EnableAlbumArtInDidl { get; set; }
|
public bool EnableAlbumArtInDidl { get; set; }
|
||||||
public bool EnableSingleAlbumArtLimit { get; set; }
|
public bool EnableSingleAlbumArtLimit { get; set; }
|
||||||
@ -272,8 +271,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
public ResponseProfile GetVideoMediaProfile(string container,
|
public ResponseProfile GetVideoMediaProfile(string container,
|
||||||
string audioCodec,
|
string audioCodec,
|
||||||
string videoCodec,
|
string videoCodec,
|
||||||
int? audioBitrate,
|
|
||||||
int? audioChannels,
|
|
||||||
int? width,
|
int? width,
|
||||||
int? height,
|
int? height,
|
||||||
int? bitDepth,
|
int? bitDepth,
|
||||||
@ -321,7 +318,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
var anyOff = false;
|
var anyOff = false;
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
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;
|
anyOff = true;
|
||||||
break;
|
break;
|
||||||
|
@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
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)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
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);
|
audioCodecProfiles.Add(i);
|
||||||
}
|
}
|
||||||
@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
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)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
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)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
@ -578,7 +578,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
// Check container conditions
|
// Check container conditions
|
||||||
foreach (ProfileCondition i in 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);
|
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
|
||||||
|
|
||||||
@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in profile.CodecProfiles)
|
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)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
@ -611,7 +611,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
foreach (ProfileCondition i in 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, "VideoCodecProfile", i, mediaSource);
|
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
|
||||||
|
|
||||||
@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in profile.CodecProfiles)
|
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)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
{
|
{
|
||||||
var hasChanges = false;
|
var hasChanges = false;
|
||||||
|
|
||||||
var images = providers.OfType<ILocalImageFileProvider>()
|
if (!(item is Photo))
|
||||||
.SelectMany(i => i.GetImages(item, directoryService))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (MergeImages(item, images))
|
|
||||||
{
|
{
|
||||||
hasChanges = true;
|
var images = providers.OfType<ILocalImageFileProvider>()
|
||||||
|
.SelectMany(i => i.GetImages(item, directoryService))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (MergeImages(item, images))
|
||||||
|
{
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasChanges;
|
return hasChanges;
|
||||||
@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
var changed = false;
|
var changed = false;
|
||||||
|
|
||||||
var newImages = images.Where(i => i.Type == type).ToList();
|
var newImages = images.Where(i => i.Type == type).ToList();
|
||||||
if (newImages.Count > 0)
|
|
||||||
{
|
var newImageFileInfos = newImages
|
||||||
var newImageFileInfos = images.Where(i => i.Type == type)
|
|
||||||
.Select(i => i.FileInfo)
|
.Select(i => i.FileInfo)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (newImageFileInfos.Count > 0)
|
if (item.AddImages(type, newImageFileInfos))
|
||||||
{
|
{
|
||||||
if (item.AddImages(type, newImageFileInfos))
|
changed = true;
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -14,6 +14,15 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
bool replaceData,
|
bool replaceData,
|
||||||
bool mergeMetadataSettings)
|
bool mergeMetadataSettings)
|
||||||
{
|
{
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
}
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("target");
|
||||||
|
}
|
||||||
|
|
||||||
if (!lockedFields.Contains(MetadataFields.Name))
|
if (!lockedFields.Contains(MetadataFields.Name))
|
||||||
{
|
{
|
||||||
if (replaceData || string.IsNullOrEmpty(target.Name))
|
if (replaceData || string.IsNullOrEmpty(target.Name))
|
||||||
|
@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
|
|
||||||
private string GetAudioImagePath(Audio item)
|
private string GetAudioImagePath(Audio item)
|
||||||
{
|
{
|
||||||
var album = item.Parent as MusicAlbum;
|
var album = item.AlbumEntity;
|
||||||
|
|
||||||
var filename = item.Album ?? string.Empty;
|
var filename = item.Album ?? string.Empty;
|
||||||
filename += string.Join(",", item.Artists.ToArray());
|
filename += string.Join(",", item.Artists.ToArray());
|
||||||
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
|
|||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
|
|||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly IHttpClient _httpClient;
|
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;
|
_fileSystem = fileSystem;
|
||||||
_config = config;
|
_config = config;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
|
_logger = logger;
|
||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
|
||||||
|
cancellationToken);
|
||||||
result.HasMetadata = result.Item != null;
|
result.HasMetadata = result.Item != null;
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
|
|||||||
// Don't fail the provider because this will just keep on going and going.
|
// 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;
|
return result;
|
||||||
}
|
}
|
||||||
@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
|
|||||||
|
|
||||||
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
||||||
usingAbsoluteData = true;
|
usingAbsoluteData = true;
|
||||||
success = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
var end = identity.IndexNumberEnd ?? episodeNumber;
|
||||||
@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
|
|||||||
episodeNumber++;
|
episodeNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success ? episode : null;
|
return episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||||||
{
|
{
|
||||||
dto.Album = audio.Album;
|
dto.Album = audio.Album;
|
||||||
|
|
||||||
var albumParent = audio.FindParent<MusicAlbum>();
|
var albumParent = audio.AlbumEntity;
|
||||||
|
|
||||||
if (albumParent != null)
|
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;
|
var hasArtist = item as IHasArtist;
|
||||||
if (hasArtist != null)
|
if (hasArtist != null)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using Mono.Nat;
|
using Mono.Nat;
|
||||||
@ -7,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@ -17,15 +19,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||||||
private readonly IServerApplicationHost _appHost;
|
private readonly IServerApplicationHost _appHost;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
private readonly ISsdpHandler _ssdp;
|
||||||
|
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
private bool _isStarted;
|
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");
|
_logger = logmanager.GetLogger("PortMapper");
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_ssdp = ssdp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _lastConfigIdentifier;
|
private string _lastConfigIdentifier;
|
||||||
@ -75,10 +79,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
_logger.Debug("Starting NAT discovery");
|
_logger.Debug("Starting NAT discovery");
|
||||||
//NatUtility.EnabledProtocols = new List<NatProtocol>
|
NatUtility.EnabledProtocols = new List<NatProtocol>
|
||||||
//{
|
{
|
||||||
// NatProtocol.Pmp
|
NatProtocol.Pmp
|
||||||
//};
|
};
|
||||||
NatUtility.DeviceFound += NatUtility_DeviceFound;
|
NatUtility.DeviceFound += NatUtility_DeviceFound;
|
||||||
|
|
||||||
// Mono.Nat does never rise this event. The event is there however it is useless.
|
// 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));
|
_timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
|
_ssdp.MessageReceived += _ssdp_MessageReceived;
|
||||||
|
|
||||||
_lastConfigIdentifier = GetConfigIdentifier();
|
_lastConfigIdentifier = GetConfigIdentifier();
|
||||||
|
|
||||||
_isStarted = true;
|
_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)
|
void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
var ex = e.ExceptionObject as Exception;
|
var ex = e.ExceptionObject as Exception;
|
||||||
@ -183,6 +199,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||||||
_timer = null;
|
_timer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ssdp.MessageReceived -= _ssdp_MessageReceived;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// This is not a significant improvement
|
// This is not a significant improvement
|
||||||
|
@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
|
|||||||
using MediaBrowser.Model.Extensions;
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Model.FileOrganization;
|
using MediaBrowser.Model.FileOrganization;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Naming.IO;
|
|
||||||
using MediaBrowser.Server.Implementations.Library;
|
using MediaBrowser.Server.Implementations.Library;
|
||||||
using MediaBrowser.Server.Implementations.Logging;
|
using MediaBrowser.Server.Implementations.Logging;
|
||||||
using System;
|
using System;
|
||||||
@ -60,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
|
|||||||
var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
|
var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
|
||||||
var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
|
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();
|
new Naming.TV.EpisodeInfo();
|
||||||
|
|
||||||
var seriesName = episodeInfo.SeriesName;
|
var seriesName = episodeInfo.SeriesName;
|
||||||
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||||||
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
|
// 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 long delays in some situations, especially over the network.
|
||||||
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
|
// 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;
|
string val;
|
||||||
_tempIgnoredPaths.TryRemove(path, out val);
|
_tempIgnoredPaths.TryRemove(path, out val);
|
||||||
@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||||||
{
|
{
|
||||||
if (_updateTimer == null)
|
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
|
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>
|
/// <returns>Task.</returns>
|
||||||
private async Task ProcessPathChanges(List<string> paths)
|
private async Task ProcessPathChanges(List<string> paths)
|
||||||
{
|
{
|
||||||
var itemsToRefresh = paths.Select(Path.GetDirectoryName)
|
var itemsToRefresh = paths
|
||||||
.Select(GetAffectedBaseItem)
|
.Select(GetAffectedBaseItem)
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Common.Extensions;
|
using Interfaces.IO;
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Common.ScheduledTasks;
|
using MediaBrowser.Common.ScheduledTasks;
|
||||||
@ -17,7 +18,6 @@ using MediaBrowser.Model.Entities;
|
|||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Naming.Audio;
|
using MediaBrowser.Naming.Audio;
|
||||||
using MediaBrowser.Naming.Common;
|
using MediaBrowser.Naming.Common;
|
||||||
using MediaBrowser.Naming.IO;
|
|
||||||
using MediaBrowser.Naming.TV;
|
using MediaBrowser.Naming.TV;
|
||||||
using MediaBrowser.Naming.Video;
|
using MediaBrowser.Naming.Video;
|
||||||
using MediaBrowser.Server.Implementations.Library.Validators;
|
using MediaBrowser.Server.Implementations.Library.Validators;
|
||||||
@ -1594,6 +1594,8 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
|
||||||
|
|
||||||
public async Task<UserView> GetNamedView(User user,
|
public async Task<UserView> GetNamedView(User user,
|
||||||
string name,
|
string name,
|
||||||
string viewType,
|
string viewType,
|
||||||
@ -1645,13 +1647,18 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
|
|
||||||
if (!refresh && item != null)
|
if (!refresh && item != null)
|
||||||
{
|
{
|
||||||
refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
|
refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refresh)
|
if (refresh)
|
||||||
{
|
{
|
||||||
await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
|
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;
|
return item;
|
||||||
@ -1731,7 +1738,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
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)
|
if (refresh)
|
||||||
{
|
{
|
||||||
@ -1767,14 +1774,13 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
var resolver = new EpisodeResolver(GetNamingOptions(),
|
var resolver = new EpisodeResolver(GetNamingOptions(),
|
||||||
new PatternsLogger());
|
new PatternsLogger());
|
||||||
|
|
||||||
var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
|
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
|
||||||
FileInfoType.Directory :
|
episode.VideoType == VideoType.HdDvd;
|
||||||
FileInfoType.File;
|
|
||||||
|
|
||||||
var locationType = episode.LocationType;
|
var locationType = episode.LocationType;
|
||||||
|
|
||||||
var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
|
var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
|
||||||
resolver.Resolve(episode.Path, fileType) :
|
resolver.Resolve(episode.Path, isFolder) :
|
||||||
new Naming.TV.EpisodeInfo();
|
new Naming.TV.EpisodeInfo();
|
||||||
|
|
||||||
if (episodeInfo == null)
|
if (episodeInfo == null)
|
||||||
@ -1928,10 +1934,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
|
|
||||||
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
|
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,
|
Id = i.FullName,
|
||||||
Type = GetFileType(i)
|
IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||||
|
|
||||||
}).ToList());
|
}).ToList());
|
||||||
|
|
||||||
@ -1962,16 +1968,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
}).OrderBy(i => i.Path).ToList();
|
}).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)
|
public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var files = fileSystemChildren.OfType<DirectoryInfo>()
|
var files = fileSystemChildren.OfType<DirectoryInfo>()
|
||||||
@ -1981,10 +1977,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||||||
|
|
||||||
var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
|
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,
|
Id = i.FullName,
|
||||||
Type = GetFileType(i)
|
IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
|
||||||
|
|
||||||
}).ToList());
|
}).ToList());
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user