aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Dlna
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Dlna')
-rw-r--r--MediaBrowser.Dlna/DlnaManager.cs18
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj1
-rw-r--r--MediaBrowser.Dlna/PlayTo/DidlBuilder.cs1
-rw-r--r--MediaBrowser.Dlna/PlayTo/DlnaController.cs104
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToManager.cs8
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs18
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlaylistItem.cs35
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs439
-rw-r--r--MediaBrowser.Dlna/PlayTo/StreamHelper.cs69
-rw-r--r--MediaBrowser.Dlna/Server/ControlHandler.cs741
-rw-r--r--MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs2
-rw-r--r--MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs12
-rw-r--r--MediaBrowser.Dlna/Server/SsdpHandler.cs2
13 files changed, 660 insertions, 790 deletions
diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs
index 83e3df798b..9993b0e21f 100644
--- a/MediaBrowser.Dlna/DlnaManager.cs
+++ b/MediaBrowser.Dlna/DlnaManager.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Dlna.Profiles;
using MediaBrowser.Dlna.Server;
@@ -27,8 +28,11 @@ namespace MediaBrowser.Dlna
private readonly IJsonSerializer _jsonSerializer;
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
+ private readonly IDtoService _dtoService;
+ private readonly IImageProcessor _imageProcessor;
+ private readonly IUserDataManager _userDataManager;
- public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IApplicationPaths appPaths, ILogger logger, IJsonSerializer jsonSerializer, IUserManager userManager, ILibraryManager libraryManager)
+ public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IApplicationPaths appPaths, ILogger logger, IJsonSerializer jsonSerializer, IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager)
{
_xmlSerializer = xmlSerializer;
_fileSystem = fileSystem;
@@ -37,6 +41,9 @@ namespace MediaBrowser.Dlna
_jsonSerializer = jsonSerializer;
_userManager = userManager;
_libraryManager = libraryManager;
+ _dtoService = dtoService;
+ _imageProcessor = imageProcessor;
+ _userDataManager = userDataManager;
//DumpProfiles();
}
@@ -502,7 +509,14 @@ namespace MediaBrowser.Dlna
public ControlResponse ProcessControlRequest(ControlRequest request)
{
- return new ControlHandler(_logger, _userManager, _libraryManager)
+ var profile = GetProfile(request.Headers)
+ ?? GetDefaultProfile();
+
+ var device = DlnaServerEntryPoint.Instance.GetServerUpnpDevice(request.TargetServerUuId);
+
+ var serverAddress = device.Descriptor.ToString().Substring(0, device.Descriptor.ToString().IndexOf("/dlna", StringComparison.OrdinalIgnoreCase));
+
+ return new ControlHandler(_logger, _userManager, _libraryManager, profile, serverAddress, _dtoService, _imageProcessor, _userDataManager)
.ProcessControlRequest(request);
}
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index bf38f19dcf..016cac4d66 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
@@ -81,7 +81,6 @@
<Compile Include="Ssdp\SsdpHelper.cs" />
<Compile Include="PlayTo\SsdpHttpClient.cs" />
<Compile Include="Common\StateVariable.cs" />
- <Compile Include="PlayTo\StreamHelper.cs" />
<Compile Include="PlayTo\TransportCommands.cs" />
<Compile Include="PlayTo\TransportStateEventArgs.cs" />
<Compile Include="PlayTo\uBaseObject.cs" />
diff --git a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
index 853064c606..0304008fc2 100644
--- a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs
@@ -39,6 +39,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <param name="serverAddress">The server address.</param>
/// <param name="streamUrl">The stream URL.</param>
/// <param name="streams">The streams.</param>
+ /// <param name="includeImageRes">if set to <c>true</c> [include image resource].</param>
/// <returns>System.String.</returns>
public static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams, bool includeImageRes)
{
diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
index 75667d54e9..183a20447d 100644
--- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs
+++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs
@@ -1,12 +1,14 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
@@ -32,6 +34,7 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IDlnaManager _dlnaManager;
private readonly IUserManager _userManager;
private readonly IServerApplicationHost _appHost;
+ private readonly IDtoService _dtoService;
private bool _playbackStarted;
private const int UpdateTimerIntervalMs = 1000;
@@ -52,7 +55,7 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
- public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager, IDlnaManager dlnaManager, IUserManager userManager, IServerApplicationHost appHost)
+ public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager, IDlnaManager dlnaManager, IUserManager userManager, IServerApplicationHost appHost, IDtoService dtoService)
{
_session = session;
_itemRepository = itemRepository;
@@ -62,6 +65,7 @@ namespace MediaBrowser.Dlna.PlayTo
_dlnaManager = dlnaManager;
_userManager = userManager;
_appHost = appHost;
+ _dtoService = dtoService;
_logger = logger;
}
@@ -172,20 +176,23 @@ namespace MediaBrowser.Dlna.PlayTo
if (playlistItem != null)
{
+ var streamInfo = playlistItem.StreamInfo;
+
if (!_playbackStarted)
{
await _sessionManager.OnPlaybackStart(new PlaybackStartInfo
{
ItemId = _currentItem.Id.ToString("N"),
SessionId = _session.Id,
- CanSeek = true,
+ CanSeek = streamInfo.RunTimeTicks.HasValue,
QueueableMediaTypes = new List<string> { _currentItem.MediaType },
- MediaSourceId = playlistItem.MediaSourceId,
- AudioStreamIndex = playlistItem.AudioStreamIndex,
- SubtitleStreamIndex = playlistItem.SubtitleStreamIndex,
+ MediaSourceId = streamInfo.MediaSourceId,
+ AudioStreamIndex = streamInfo.AudioStreamIndex,
+ SubtitleStreamIndex = streamInfo.SubtitleStreamIndex,
IsMuted = _device.IsMuted,
IsPaused = _device.IsPaused,
- VolumeLevel = _device.Volume
+ VolumeLevel = _device.Volume,
+ PlayMethod = streamInfo.IsDirectStream ? PlayMethod.DirectStream : PlayMethod.Transcode
}).ConfigureAwait(false);
@@ -196,9 +203,9 @@ namespace MediaBrowser.Dlna.PlayTo
{
var ticks = _device.Position.Ticks;
- if (playlistItem.Transcode)
+ if (!streamInfo.IsDirectStream)
{
- ticks += playlistItem.StartPositionTicks;
+ ticks += streamInfo.StartPositionTicks;
}
await _sessionManager.OnPlaybackProgress(new PlaybackProgressInfo
@@ -208,11 +215,12 @@ namespace MediaBrowser.Dlna.PlayTo
PositionTicks = ticks,
IsMuted = _device.IsMuted,
IsPaused = _device.IsPaused,
- MediaSourceId = playlistItem.MediaSourceId,
- AudioStreamIndex = playlistItem.AudioStreamIndex,
- SubtitleStreamIndex = playlistItem.SubtitleStreamIndex,
+ MediaSourceId = streamInfo.MediaSourceId,
+ AudioStreamIndex = streamInfo.AudioStreamIndex,
+ SubtitleStreamIndex = streamInfo.SubtitleStreamIndex,
VolumeLevel = _device.Volume,
- CanSeek = true
+ CanSeek = streamInfo.RunTimeTicks.HasValue,
+ PlayMethod = streamInfo.IsDirectStream ? PlayMethod.DirectStream : PlayMethod.Transcode
}).ConfigureAwait(false);
}
@@ -411,46 +419,43 @@ namespace MediaBrowser.Dlna.PlayTo
private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
{
- var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery
- {
- ItemId = item.Id
-
- }).ToList();
-
var deviceInfo = _device.Properties;
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
- var playlistItem = GetPlaylistItem(item, streams, profile);
- playlistItem.StartPositionTicks = startPostionTicks;
- playlistItem.DeviceProfileId = profile.Id;
+ var mediaSources = item is Audio || item is Video
+ ? _dtoService.GetMediaSources(item)
+ : new List<MediaSourceInfo>();
- if (playlistItem.MediaType == DlnaProfileType.Audio)
- {
- playlistItem.StreamUrl = StreamHelper.GetAudioUrl(deviceInfo, playlistItem, streams, serverAddress);
- }
- else
- {
- playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
- }
+ var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId);
+ playlistItem.StreamInfo.StartPositionTicks = startPostionTicks;
+
+ playlistItem.StreamUrl = playlistItem.StreamInfo.ToUrl(serverAddress);
- playlistItem.Didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams, profile.EnableAlbumArtInDidl);
+ var mediaStreams = mediaSources
+ .Where(i => string.Equals(i.Id, playlistItem.StreamInfo.MediaSourceId))
+ .SelectMany(i => i.MediaStreams)
+ .ToList();
+
+ playlistItem.Didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, mediaStreams, profile.EnableAlbumArtInDidl);
return playlistItem;
}
private string GetDlnaHeaders(PlaylistItem item)
{
- var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
+ var streamInfo = item.StreamInfo;
+
+ var orgOp = !streamInfo.IsDirectStream ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
- var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
+ var orgCi = !streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
string contentFeatures;
- var container = item.Container.TrimStart('.');
+ var container = streamInfo.Container.TrimStart('.');
if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
{
@@ -488,7 +493,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
}
- else if (item.MediaType == DlnaProfileType.Video)
+ else if (streamInfo.MediaType == DlnaProfileType.Video)
{
// Default to AVI for video
contentFeatures = "DLNA.ORG_PN=AVI";
@@ -502,20 +507,38 @@ namespace MediaBrowser.Dlna.PlayTo
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
}
- private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaStream> mediaStreams, DeviceProfile profile)
+ private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaSourceInfo> mediaSources, DeviceProfile profile, string deviceId)
{
var video = item as Video;
if (video != null)
{
- return new PlaylistItemFactory().Create(video, mediaStreams, profile);
+ return new PlaylistItem
+ {
+ StreamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
+ {
+ ItemId = item.Id.ToString("N"),
+ MediaSources = mediaSources,
+ Profile = profile,
+ DeviceId = deviceId
+ })
+ };
}
var audio = item as Audio;
if (audio != null)
{
- return new PlaylistItemFactory().Create(audio, mediaStreams, profile);
+ return new PlaylistItem
+ {
+ StreamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
+ {
+ ItemId = item.Id.ToString("N"),
+ MediaSources = mediaSources,
+ Profile = profile,
+ DeviceId = deviceId
+ })
+ };
}
var photo = item as Photo;
@@ -578,8 +601,9 @@ namespace MediaBrowser.Dlna.PlayTo
await _device.SetAvTransport(nextTrack.StreamUrl, dlnaheaders, nextTrack.Didl);
- if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
- await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
+ var streamInfo = nextTrack.StreamInfo;
+ if (streamInfo.StartPositionTicks > 0 && streamInfo.IsDirectStream)
+ await _device.Seek(TimeSpan.FromTicks(streamInfo.StartPositionTicks));
return true;
}
@@ -602,7 +626,7 @@ namespace MediaBrowser.Dlna.PlayTo
return Task.FromResult(false);
prevTrack.PlayState = 1;
- return _device.SetAvTransport(prevTrack.StreamUrl, GetDlnaHeaders(prevTrack), prevTrack.Didl);
+ return _device.SetAvTransport(prevTrack.StreamInfo.ToDlnaUrl(GetServerAddress()), GetDlnaHeaders(prevTrack), prevTrack.Didl);
}
#endregion
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index 5cc3f13e54..655a11693f 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -2,11 +2,11 @@
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Dlna.Ssdp;
-using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
@@ -37,8 +37,9 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IDlnaManager _dlnaManager;
private readonly IServerConfigurationManager _config;
private readonly IServerApplicationHost _appHost;
+ private readonly IDtoService _dtoService;
- public PlayToManager(ILogger logger, IServerConfigurationManager config, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepository, ILibraryManager libraryManager, INetworkManager networkManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost)
+ public PlayToManager(ILogger logger, IServerConfigurationManager config, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepository, ILibraryManager libraryManager, INetworkManager networkManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IDtoService dtoService)
{
_locations = new ConcurrentDictionary<string, DateTime>();
_tokenSource = new CancellationTokenSource();
@@ -52,6 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo
_userManager = userManager;
_dlnaManager = dlnaManager;
_appHost = appHost;
+ _dtoService = dtoService;
_config = config;
}
@@ -248,7 +250,7 @@ namespace MediaBrowser.Dlna.PlayTo
if (controller == null)
{
- sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager, _appHost);
+ sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager, _appHost, _dtoService);
controller.Init(device);
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs b/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs
index 91b03bc238..c0af1295fb 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Plugins;
@@ -24,8 +25,9 @@ namespace MediaBrowser.Dlna.PlayTo
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
private readonly IServerApplicationHost _appHost;
+ private readonly IDtoService _dtoService;
- public PlayToServerEntryPoint(ILogManager logManager, IServerConfigurationManager config, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepo, ILibraryManager libraryManager, INetworkManager networkManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost)
+ public PlayToServerEntryPoint(ILogManager logManager, IServerConfigurationManager config, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepo, ILibraryManager libraryManager, INetworkManager networkManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IDtoService dtoService)
{
_config = config;
_sessionManager = sessionManager;
@@ -36,6 +38,7 @@ namespace MediaBrowser.Dlna.PlayTo
_userManager = userManager;
_dlnaManager = dlnaManager;
_appHost = appHost;
+ _dtoService = dtoService;
_logger = logManager.GetLogger("PlayTo");
}
@@ -72,7 +75,18 @@ namespace MediaBrowser.Dlna.PlayTo
{
try
{
- _manager = new PlayToManager(_logger, _config, _sessionManager, _httpClient, _itemRepo, _libraryManager, _networkManager, _userManager, _dlnaManager, _appHost);
+ _manager = new PlayToManager(_logger,
+ _config,
+ _sessionManager,
+ _httpClient,
+ _itemRepo,
+ _libraryManager,
+ _networkManager,
+ _userManager,
+ _dlnaManager,
+ _appHost,
+ _dtoService);
+
_manager.Start();
}
catch (Exception ex)
diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
index be6e9a0c94..95167cfe92 100644
--- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs
@@ -4,45 +4,12 @@ namespace MediaBrowser.Dlna.PlayTo
{
public class PlaylistItem
{
- public string ItemId { get; set; }
-
- public string MediaSourceId { get; set; }
-
- public bool Transcode { get; set; }
-
- public DlnaProfileType MediaType { get; set; }
-
- public string Container { get; set; }
-
public int PlayState { get; set; }
public string StreamUrl { get; set; }
public string Didl { get; set; }
- public long StartPositionTicks { get; set; }
-
- public string VideoCodec { get; set; }
-
- public string AudioCodec { get; set; }
-
- public int? AudioStreamIndex { get; set; }
-
- public int? SubtitleStreamIndex { get; set; }
-
- public int? MaxAudioChannels { get; set; }
-
- public int? AudioBitrate { get; set; }
-
- public int? VideoBitrate { get; set; }
-
- public int? VideoLevel { get; set; }
-
- public int? MaxWidth { get; set; }
- public int? MaxHeight { get; set; }
-
- public int? MaxFramerate { get; set; }
-
- public string DeviceProfileId { get; set; }
+ public StreamInfo StreamInfo { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
index 34394fa32d..29d44bca0e 100644
--- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs
@@ -1,10 +1,6 @@
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Entities;
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -15,235 +11,40 @@ namespace MediaBrowser.Dlna.PlayTo
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public PlaylistItem Create(Audio item, List<MediaStream> mediaStreams, DeviceProfile profile)
+ public PlaylistItem Create(Photo item, DeviceProfile profile)
{
var playlistItem = new PlaylistItem
{
- ItemId = item.Id.ToString("N"),
- MediaType = DlnaProfileType.Audio
- };
-
- var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
-
- var directPlay = profile.DirectPlayProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
-
- if (directPlay != null)
- {
- var audioCodec = audioStream == null ? null : audioStream.Codec;
-
- // Make sure audio codec profiles are satisfied
- if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
- .All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream)))
+ StreamInfo = new StreamInfo
{
- playlistItem.Transcode = false;
- playlistItem.Container = Path.GetExtension(item.Path);
-
- return playlistItem;
+ ItemId = item.Id.ToString("N"),
+ MediaType = DlnaProfileType.Photo,
}
- }
-
- var transcodingProfile = profile.TranscodingProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
-
- if (transcodingProfile != null)
- {
- playlistItem.Transcode = true;
- playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
- playlistItem.AudioCodec = transcodingProfile.AudioCodec;
-
- var audioTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
- .Take(1)
- .SelectMany(i => i.Conditions);
-
- ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
- }
-
- return playlistItem;
- }
-
- public PlaylistItem Create(Photo item, DeviceProfile profile)
- {
- var playlistItem = new PlaylistItem
- {
- ItemId = item.Id.ToString("N"),
- MediaType = DlnaProfileType.Photo
};
var directPlay = profile.DirectPlayProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item));
+ .FirstOrDefault(i => i.Type == DlnaProfileType.Photo && IsSupported(i, item));
if (directPlay != null)
{
- playlistItem.Transcode = false;
- playlistItem.Container = Path.GetExtension(item.Path);
+ playlistItem.StreamInfo.IsDirectStream = true;
+ playlistItem.StreamInfo.Container = Path.GetExtension(item.Path);
return playlistItem;
}
var transcodingProfile = profile.TranscodingProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
+ .FirstOrDefault(i => i.Type == DlnaProfileType.Photo);
if (transcodingProfile != null)
{
- playlistItem.Transcode = true;
- playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
+ playlistItem.StreamInfo.IsDirectStream = true;
+ playlistItem.StreamInfo.Container = "." + transcodingProfile.Container.TrimStart('.');
}
return playlistItem;
}
- public PlaylistItem Create(Video item, List<MediaStream> mediaStreams, DeviceProfile profile)
- {
- var playlistItem = new PlaylistItem
- {
- ItemId = item.Id.ToString("N"),
- MediaType = DlnaProfileType.Video
- };
-
- var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
- var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
-
- var directPlay = profile.DirectPlayProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
-
- if (directPlay != null)
- {
- var videoCodec = videoStream == null ? null : videoStream.Codec;
-
- // Make sure video codec profiles are satisfied
- if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
- .All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
- {
- var audioCodec = audioStream == null ? null : audioStream.Codec;
-
- // Make sure audio codec profiles are satisfied
- if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
- .All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
- {
- playlistItem.Transcode = false;
- playlistItem.Container = Path.GetExtension(item.Path);
-
- return playlistItem;
- }
- }
- }
-
- var transcodingProfile = profile.TranscodingProfiles
- .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
-
- if (transcodingProfile != null)
- {
- playlistItem.Transcode = true;
- playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
- playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault();
- playlistItem.VideoCodec = transcodingProfile.VideoCodec;
-
- var videoTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
- .Take(1)
- .SelectMany(i => i.Conditions);
-
- ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
-
- var audioTranscodingConditions = profile.CodecProfiles
- .Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
- .Take(1)
- .SelectMany(i => i.Conditions);
-
- ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
- }
-
- return playlistItem;
- }
-
- private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> conditions)
- {
- foreach (var condition in conditions
- .Where(i => !string.IsNullOrEmpty(i.Value)))
- {
- var value = condition.Value;
-
- switch (condition.Property)
- {
- case ProfileConditionValue.AudioBitrate:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.AudioBitrate = num;
- }
- break;
- }
- case ProfileConditionValue.AudioChannels:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.MaxAudioChannels = num;
- }
- break;
- }
- case ProfileConditionValue.AudioProfile:
- case ProfileConditionValue.Has64BitOffsets:
- case ProfileConditionValue.VideoBitDepth:
- case ProfileConditionValue.VideoProfile:
- {
- // Not supported yet
- break;
- }
- case ProfileConditionValue.Height:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.MaxHeight = num;
- }
- break;
- }
- case ProfileConditionValue.VideoBitrate:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.VideoBitrate = num;
- }
- break;
- }
- case ProfileConditionValue.VideoFramerate:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.MaxFramerate = num;
- }
- break;
- }
- case ProfileConditionValue.VideoLevel:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.VideoLevel = num;
- }
- break;
- }
- case ProfileConditionValue.Width:
- {
- int num;
- if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
- {
- item.MaxWidth = num;
- }
- break;
- }
- default:
- throw new ArgumentException("Unrecognized ProfileConditionValue");
- }
- }
- }
-
private bool IsSupported(DirectPlayProfile profile, Photo item)
{
var mediaPath = item.Path;
@@ -260,223 +61,5 @@ namespace MediaBrowser.Dlna.PlayTo
return true;
}
-
- private bool IsSupported(DirectPlayProfile profile, Audio item, MediaStream audioStream)
- {
- var mediaPath = item.Path;
-
- if (profile.Container.Length > 0)
- {
- // Check container type
- var mediaContainer = Path.GetExtension(mediaPath);
- if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
- {
- return false;
- }
- }
-
- return true;
- }
-
- private bool IsSupported(DirectPlayProfile profile, Video item, MediaStream videoStream, MediaStream audioStream)
- {
- if (item.VideoType != VideoType.VideoFile)
- {
- return false;
- }
-
- var mediaPath = item.Path;
-
- if (profile.Container.Length > 0)
- {
- // Check container type
- var mediaContainer = Path.GetExtension(mediaPath);
- if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
- {
- return false;
- }
- }
-
- // Check video codec
- var videoCodecs = profile.GetVideoCodecs();
- if (videoCodecs.Count > 0)
- {
- var videoCodec = videoStream == null ? null : videoStream.Codec;
- if (string.IsNullOrWhiteSpace(videoCodec) || !videoCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- var audioCodecs = profile.GetAudioCodecs();
- if (audioCodecs.Count > 0)
- {
- // Check audio codecs
- var audioCodec = audioStream == null ? null : audioStream.Codec;
- if (string.IsNullOrWhiteSpace(audioCodec) || !audioCodecs.Contains(audioCodec, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- return true;
- }
-
- private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Audio item)
- {
- // Placeholder for future conditions
- return true;
- }
-
- private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Photo item)
- {
- // Placeholder for future conditions
- return true;
- }
-
- private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Video item)
- {
- // Placeholder for future conditions
- return true;
- }
-
- private bool AreConditionsSatisfied(IEnumerable<ProfileCondition> conditions, string mediaPath, MediaStream videoStream, MediaStream audioStream)
- {
- return conditions.All(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream));
- }
-
- /// <summary>
- /// Determines whether [is condition satisfied] [the specified condition].
- /// </summary>
- /// <param name="condition">The condition.</param>
- /// <param name="mediaPath">The media path.</param>
- /// <param name="videoStream">The video stream.</param>
- /// <param name="audioStream">The audio stream.</param>
- /// <returns><c>true</c> if [is condition satisfied] [the specified condition]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.InvalidOperationException">Unexpected ProfileConditionType</exception>
- private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
- {
- if (condition.Property == ProfileConditionValue.Has64BitOffsets)
- {
- // TODO: Determine how to evaluate this
- }
-
- if (condition.Property == ProfileConditionValue.VideoProfile)
- {
- var profile = videoStream == null ? null : videoStream.Profile;
-
- if (!string.IsNullOrWhiteSpace(profile))
- {
- switch (condition.Condition)
- {
- case ProfileConditionType.Equals:
- return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
- case ProfileConditionType.NotEquals:
- return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
- default:
- throw new InvalidOperationException("Unexpected ProfileConditionType");
- }
- }
- }
-
- else if (condition.Property == ProfileConditionValue.AudioProfile)
- {
- var profile = audioStream == null ? null : audioStream.Profile;
-
- if (!string.IsNullOrWhiteSpace(profile))
- {
- switch (condition.Condition)
- {
- case ProfileConditionType.Equals:
- return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
- case ProfileConditionType.NotEquals:
- return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
- default:
- throw new InvalidOperationException("Unexpected ProfileConditionType");
- }
- }
- }
-
- else
- {
- var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream);
-
- if (actualValue.HasValue)
- {
- long expected;
- if (long.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected))
- {
- switch (condition.Condition)
- {
- case ProfileConditionType.Equals:
- return actualValue.Value == expected;
- case ProfileConditionType.GreaterThanEqual:
- return actualValue.Value >= expected;
- case ProfileConditionType.LessThanEqual:
- return actualValue.Value <= expected;
- case ProfileConditionType.NotEquals:
- return actualValue.Value != expected;
- default:
- throw new InvalidOperationException("Unexpected ProfileConditionType");
- }
- }
- }
- }
-
- // Value doesn't exist in metadata. Fail it if required.
- return !condition.IsRequired;
- }
-
- /// <summary>
- /// Gets the condition value.
- /// </summary>
- /// <param name="condition">The condition.</param>
- /// <param name="mediaPath">The media path.</param>
- /// <param name="videoStream">The video stream.</param>
- /// <param name="audioStream">The audio stream.</param>
- /// <returns>System.Nullable{System.Int64}.</returns>
- /// <exception cref="System.InvalidOperationException">Unexpected Property</exception>
- private long? GetConditionValue(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
- {
- switch (condition.Property)
- {
- case ProfileConditionValue.AudioBitrate:
- return audioStream == null ? null : audioStream.BitRate;
- case ProfileConditionValue.AudioChannels:
- return audioStream == null ? null : audioStream.Channels;
- case ProfileConditionValue.VideoBitrate:
- return videoStream == null ? null : videoStream.BitRate;
- case ProfileConditionValue.VideoFramerate:
- return videoStream == null ? null : (ConvertToLong(videoStream.AverageFrameRate ?? videoStream.RealFrameRate));
- case ProfileConditionValue.Height:
- return videoStream == null ? null : videoStream.Height;
- case ProfileConditionValue.Width:
- return videoStream == null ? null : videoStream.Width;
- case ProfileConditionValue.VideoLevel:
- return videoStream == null ? null : ConvertToLong(videoStream.Level);
- default:
- throw new InvalidOperationException("Unexpected Property");
- }
- }
-
- /// <summary>
- /// Converts to long.
- /// </summary>
- /// <param name="val">The value.</param>
- /// <returns>System.Nullable{System.Int64}.</returns>
- private long? ConvertToLong(float? val)
- {
- return val.HasValue ? Convert.ToInt64(val.Value) : (long?)null;
- }
-
- /// <summary>
- /// Converts to long.
- /// </summary>
- /// <param name="val">The value.</param>
- /// <returns>System.Nullable{System.Int64}.</returns>
- private long? ConvertToLong(double? val)
- {
- return val.HasValue ? Convert.ToInt64(val.Value) : (long?)null;
- }
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs
deleted file mode 100644
index b65e94fd11..0000000000
--- a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-using System.Globalization;
-
-namespace MediaBrowser.Dlna.PlayTo
-{
- class StreamHelper
- {
- /// <summary>
- /// Gets the audio URL.
- /// </summary>
- /// <param name="deviceProperties">The device properties.</param>
- /// <param name="item">The item.</param>
- /// <param name="streams">The streams.</param>
- /// <param name="serverAddress">The server address.</param>
- /// <returns>System.String.</returns>
- internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
- {
- var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
-
- return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand);
- }
-
- /// <summary>
- /// Gets the video URL.
- /// </summary>
- /// <param name="deviceProperties">The device properties.</param>
- /// <param name="item">The item.</param>
- /// <param name="streams">The streams.</param>
- /// <param name="serverAddress">The server address.</param>
- /// <returns>The url to send to the device</returns>
- internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
- {
- var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
-
- return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
- }
-
- /// <summary>
- /// Builds the dlna URL.
- /// </summary>
- private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item)
- {
- var usCulture = new CultureInfo("en-US");
-
- var list = new List<string>
- {
- item.DeviceProfileId ?? string.Empty,
- deviceProperties.UUID ?? string.Empty,
- item.MediaSourceId ?? string.Empty,
- (!item.Transcode).ToString().ToLower(),
- item.VideoCodec ?? string.Empty,
- item.AudioCodec ?? string.Empty,
- item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(usCulture) : string.Empty,
- item.SubtitleStreamIndex.HasValue ? item.SubtitleStreamIndex.Value.ToString(usCulture) : string.Empty,
- item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(usCulture) : string.Empty,
- item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(usCulture) : string.Empty,
- item.MaxAudioChannels.HasValue ? item.MaxAudioChannels.Value.ToString(usCulture) : string.Empty,
- item.MaxFramerate.HasValue ? item.MaxFramerate.Value.ToString(usCulture) : string.Empty,
- item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty,
- item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty,
- item.StartPositionTicks.ToString(usCulture),
- item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty
- };
-
- return string.Format("Params={0}", string.Join(";", list.ToArray()));
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Dlna/Server/ControlHandler.cs b/MediaBrowser.Dlna/Server/ControlHandler.cs
index d05062f383..c3a3c0bf00 100644
--- a/MediaBrowser.Dlna/Server/ControlHandler.cs
+++ b/MediaBrowser.Dlna/Server/ControlHandler.cs
@@ -1,15 +1,23 @@
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Xml;
namespace MediaBrowser.Dlna.Server
@@ -19,7 +27,12 @@ namespace MediaBrowser.Dlna.Server
private readonly ILogger _logger;
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
- private DeviceProfile _profile;
+ private readonly DeviceProfile _profile;
+ private readonly IDtoService _dtoService;
+ private readonly IImageProcessor _imageProcessor;
+ private readonly IUserDataManager _userDataManager;
+
+ private readonly string _serverAddress;
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
@@ -31,11 +44,16 @@ namespace MediaBrowser.Dlna.Server
private int systemID = 0;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
- public ControlHandler(ILogger logger, IUserManager userManager, ILibraryManager libraryManager)
+ public ControlHandler(ILogger logger, IUserManager userManager, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager)
{
_logger = logger;
_userManager = userManager;
_libraryManager = libraryManager;
+ _profile = profile;
+ _serverAddress = serverAddress;
+ _dtoService = dtoService;
+ _imageProcessor = imageProcessor;
+ _userDataManager = userDataManager;
}
public ControlResponse ProcessControlRequest(ControlRequest request)
@@ -46,6 +64,8 @@ namespace MediaBrowser.Dlna.Server
}
catch (Exception ex)
{
+ _logger.ErrorException("Error processing control request", ex);
+
return GetErrorResponse(ex);
}
}
@@ -120,7 +140,8 @@ namespace MediaBrowser.Dlna.Server
var controlResponse = new ControlResponse
{
- Xml = env.OuterXml
+ Xml = env.OuterXml,
+ IsSuccessful = true
};
controlResponse.Headers.Add("EXT", string.Empty);
@@ -153,7 +174,8 @@ namespace MediaBrowser.Dlna.Server
return new ControlResponse
{
- Xml = env.OuterXml
+ Xml = env.OuterXml,
+ IsSuccessful = false
};
}
@@ -161,7 +183,16 @@ namespace MediaBrowser.Dlna.Server
{
var id = sparams["ObjectID"];
- var newbookmark = long.Parse(sparams["PosSecond"]);
+ var item = _libraryManager.GetItemById(new Guid(id));
+
+ var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
+
+ var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+
+ userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
+
+ _userDataManager.SaveUserData(user.Id, item, userdata, UserDataSaveReason.TogglePlayed,
+ CancellationToken.None);
return new Headers();
}
@@ -209,13 +240,13 @@ namespace MediaBrowser.Dlna.Server
var id = sparams["ObjectID"];
var flag = sparams["BrowseFlag"];
- int requested = 20;
var provided = 0;
+ int requested = 0;
int start = 0;
if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out requested) && requested <= 0)
{
- requested = 20;
+ requested = 0;
}
if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out start) && start <= 0)
{
@@ -232,11 +263,11 @@ namespace MediaBrowser.Dlna.Server
didl.SetAttribute("xmlns:sec", NS_SEC);
result.AppendChild(didl);
- var folder = string.IsNullOrWhiteSpace(id)
+ var folder = string.IsNullOrWhiteSpace(id) || string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
? user.RootFolder
: (Folder)_libraryManager.GetItemById(new Guid(id));
- var children = folder.GetChildren(user, true).ToList();
+ var children = GetChildrenSorted(folder, user).ToList();
if (string.Equals(flag, "BrowseMetadata"))
{
@@ -245,40 +276,29 @@ namespace MediaBrowser.Dlna.Server
}
else
{
- foreach (var i in children.OfType<Folder>())
+ if (start > 0)
{
- if (start > 0)
- {
- start--;
- continue;
- }
-
- var childCount = i.GetChildren(user, true).Count();
-
- Browse_AddFolder(result, i, childCount);
-
- if (++provided == requested)
- {
- break;
- }
+ children = children.Skip(start).ToList();
+ }
+ if (requested > 0)
+ {
+ children = children.Take(requested).ToList();
}
- if (provided != requested)
+ provided = children.Count;
+
+ foreach (var i in children)
{
- foreach (var i in children.Where(i => !i.IsFolder))
+ if (i.IsFolder)
{
- if (start > 0)
- {
- start--;
- continue;
- }
+ var f = (Folder)i;
+ var childCount = GetChildrenSorted(f, user).Count();
+ Browse_AddFolder(result, f, childCount);
+ }
+ else
+ {
Browse_AddItem(result, i, user);
-
- if (++provided == requested)
- {
- break;
- }
}
}
}
@@ -294,10 +314,23 @@ namespace MediaBrowser.Dlna.Server
};
}
+ private IEnumerable<BaseItem> GetChildrenSorted(Folder folder, User user)
+ {
+ var children = folder.GetChildren(user, true).Where(i => i.LocationType != LocationType.Virtual);
+
+ if (folder is Series || folder is Season || folder is BoxSet)
+ {
+ return children;
+ }
+
+ return _libraryManager.Sort(children, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending);
+ }
+
private void Browse_AddFolder(XmlDocument result, Folder f, int childCount)
{
var container = result.CreateElement(string.Empty, "container", NS_DIDL);
container.SetAttribute("restricted", "0");
+ container.SetAttribute("searchable", "1");
container.SetAttribute("childCount", childCount.ToString(_usCulture));
container.SetAttribute("id", f.Id.ToString("N"));
@@ -311,20 +344,28 @@ namespace MediaBrowser.Dlna.Server
container.SetAttribute("parentID", parent.Id.ToString("N"));
}
- var title = result.CreateElement("dc", "title", NS_DC);
- title.InnerText = f.Name;
- container.AppendChild(title);
+ AddCommonFields(f, container);
- var date = result.CreateElement("dc", "date", NS_DC);
- date.InnerText = f.DateModified.ToString("o");
- container.AppendChild(date);
+ AddCover(f, container);
- var objectClass = result.CreateElement("upnp", "class", NS_UPNP);
- objectClass.InnerText = "object.container.storageFolder";
- container.AppendChild(objectClass);
+ container.AppendChild(CreateObjectClass(result, f));
result.DocumentElement.AppendChild(container);
}
+ private void AddValue(XmlElement elem, string prefix, string name, string value, string namespaceUri)
+ {
+ try
+ {
+ var date = elem.OwnerDocument.CreateElement(prefix, name, namespaceUri);
+ date.InnerText = value;
+ elem.AppendChild(date);
+ }
+ catch (XmlException)
+ {
+ //_logger.Error("Error adding xml value: " + value);
+ }
+ }
+
private void Browse_AddItem(XmlDocument result, BaseItem item, User user)
{
var element = result.CreateElement(string.Empty, "item", NS_DIDL);
@@ -342,52 +383,222 @@ namespace MediaBrowser.Dlna.Server
AddGeneralProperties(item, element);
- AddActors(item, element);
+ // refID?
+ // storeAttribute(itemNode, object, ClassProperties.REF_ID, false);
- var title = result.CreateElement("dc", "title", NS_DC);
- title.InnerText = item.Name;
- element.AppendChild(title);
-
- var res = result.CreateElement(string.Empty, "res", NS_DIDL);
-
- //res.InnerText = String.Format(
- // "http://{0}:{1}{2}file/{3}",
- // request.LocalEndPoint.Address,
- // request.LocalEndPoint.Port,
- // prefix,
- // resource.Id
- // );
-
- //if (props.TryGetValue("SizeRaw", out prop))
- //{
- // res.SetAttribute("size", prop);
- //}
- //if (props.TryGetValue("Resolution", out prop))
- //{
- // res.SetAttribute("resolution", prop);
- //}
- //if (props.TryGetValue("Duration", out prop))
- //{
- // res.SetAttribute("duration", prop);
- //}
-
- //res.SetAttribute("protocolInfo", String.Format(
- // "http-get:*:{1}:{0};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}",
- // resource.PN, DlnaMaps.Mime[resource.Type], DlnaMaps.DefaultStreaming
- // ));
+ var audio = item as Audio;
+ if (audio != null)
+ {
+ AddAudioResource(element, audio);
+ }
- element.AppendChild(res);
+ var video = item as Video;
+ if (video != null)
+ {
+ AddVideoResource(element, video);
+ }
AddCover(item, element);
result.DocumentElement.AppendChild(element);
}
+ private string GetDeviceId()
+ {
+ return "erer";
+ }
+
+ private void AddVideoResource(XmlElement container, Video video)
+ {
+ var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
+
+ var sources = _dtoService.GetMediaSources(video);
+
+ int? maxBitrateSetting = null;
+
+ var streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
+ {
+ ItemId = video.Id.ToString("N"),
+ MediaSources = sources,
+ Profile = _profile,
+ DeviceId = GetDeviceId(),
+ MaxBitrate = maxBitrateSetting
+ });
+
+ var url = streamInfo.ToDlnaUrl(_serverAddress);
+ res.InnerText = url;
+
+ var mediaSource = sources.First(i => string.Equals(i.Id, streamInfo.MediaSourceId));
+
+ if (mediaSource.RunTimeTicks.HasValue)
+ {
+ res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
+ }
+
+ if (streamInfo.IsDirectStream && mediaSource.Size.HasValue)
+ {
+ res.SetAttribute("size", mediaSource.Size.Value.ToString(_usCulture));
+ }
+
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video && !string.Equals(i.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase));
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+
+ var targetAudioBitrate = streamInfo.AudioBitrate ?? (audioStream == null ? null : audioStream.BitRate);
+ var targetSampleRate = audioStream == null ? null : audioStream.SampleRate;
+ var targetChannels = streamInfo.MaxAudioChannels ?? (audioStream == null ? null : audioStream.Channels);
+
+ var targetWidth = streamInfo.MaxWidth ?? (videoStream == null ? null : videoStream.Width);
+ var targetHeight = streamInfo.MaxHeight ?? (videoStream == null ? null : videoStream.Height);
+
+ var targetVideoCodec = streamInfo.IsDirectStream
+ ? (videoStream == null ? null : videoStream.Codec)
+ : streamInfo.VideoCodec;
+
+ var targetAudioCodec = streamInfo.IsDirectStream
+ ? (audioStream == null ? null : audioStream.Codec)
+ : streamInfo.AudioCodec;
+
+ var targetBitrate = maxBitrateSetting ?? mediaSource.Bitrate;
+
+ if (targetChannels.HasValue)
+ {
+ res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
+ }
+
+ if (targetWidth.HasValue && targetHeight.HasValue)
+ {
+ res.SetAttribute("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
+ }
+
+ if (targetSampleRate.HasValue)
+ {
+ res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
+ }
+
+ if (targetAudioBitrate.HasValue)
+ {
+ res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
+ }
+
+ var formatProfile = new MediaFormatProfileResolver().ResolveVideoFormat(streamInfo.Container,
+ targetVideoCodec,
+ targetAudioCodec,
+ targetWidth,
+ targetHeight,
+ targetBitrate,
+ TransportStreamTimestamp.NONE);
+
+ var filename = url.Substring(0, url.IndexOf('?'));
+
+ var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo);
+
+ var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
+
+ res.SetAttribute("protocolInfo", String.Format(
+ "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}",
+ MimeTypes.GetMimeType(filename),
+ formatProfile,
+ orgOpValue,
+ orgCi,
+ DlnaMaps.DefaultStreaming
+ ));
+
+ container.AppendChild(res);
+ }
+
+ private void AddAudioResource(XmlElement container, Audio audio)
+ {
+ var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
+
+ var sources = _dtoService.GetMediaSources(audio);
+
+ var streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
+ {
+ ItemId = audio.Id.ToString("N"),
+ MediaSources = sources,
+ Profile = _profile,
+ DeviceId = GetDeviceId()
+ });
+
+ var url = streamInfo.ToDlnaUrl(_serverAddress);
+ res.InnerText = url;
+
+ var mediaSource = sources.First(i => string.Equals(i.Id, streamInfo.MediaSourceId));
+
+ if (mediaSource.RunTimeTicks.HasValue)
+ {
+ res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
+ }
+
+ if (streamInfo.IsDirectStream && mediaSource.Size.HasValue)
+ {
+ res.SetAttribute("size", mediaSource.Size.Value.ToString(_usCulture));
+ }
+
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+
+ var targetAudioBitrate = streamInfo.AudioBitrate ?? (audioStream == null ? null : audioStream.BitRate);
+ var targetSampleRate = audioStream == null ? null : audioStream.SampleRate;
+ var targetChannels = streamInfo.MaxAudioChannels ?? (audioStream == null ? null : audioStream.Channels);
+
+ if (targetChannels.HasValue)
+ {
+ res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
+ }
+
+ if (targetSampleRate.HasValue)
+ {
+ res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
+ }
+
+ if (targetAudioBitrate.HasValue)
+ {
+ res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
+ }
+
+ var formatProfile = new MediaFormatProfileResolver().ResolveAudioFormat(streamInfo.Container, targetAudioBitrate, targetSampleRate, targetChannels);
+
+ var filename = url.Substring(0, url.IndexOf('?'));
+
+ var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo);
+
+ var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
+
+ res.SetAttribute("protocolInfo", String.Format(
+ "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}",
+ MimeTypes.GetMimeType(filename),
+ formatProfile,
+ orgOpValue,
+ orgCi,
+ DlnaMaps.DefaultStreaming
+ ));
+
+ container.AppendChild(res);
+ }
+
private XmlElement CreateObjectClass(XmlDocument result, BaseItem item)
{
var objectClass = result.CreateElement("upnp", "class", NS_UPNP);
- if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
+ if (item.IsFolder)
+ {
+ string classType = null;
+
+ if (!_profile.RequiresPlainFolders)
+ {
+ if (item is MusicAlbum)
+ {
+ classType = "object.container.musicAlbum";
+ }
+ if (item is MusicArtist)
+ {
+ classType = "object.container.musicArtist";
+ }
+ }
+
+ objectClass.InnerText = classType ?? "object.container.storageFolder";
+ }
+ else if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
{
objectClass.InnerText = "object.item.audioItem.musicTrack";
}
@@ -397,7 +608,14 @@ namespace MediaBrowser.Dlna.Server
}
else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
- objectClass.InnerText = "object.item.videoItem.movie";
+ if (!_profile.RequiresPlainVideoItems && item is Movie)
+ {
+ objectClass.InnerText = "object.item.videoItem.movie";
+ }
+ else
+ {
+ objectClass.InnerText = "object.item.videoItem";
+ }
}
else
{
@@ -407,152 +625,259 @@ namespace MediaBrowser.Dlna.Server
return objectClass;
}
- private void AddActors(BaseItem item, XmlElement element)
+ private void AddPeople(BaseItem item, XmlElement element)
{
foreach (var actor in item.People)
{
- var e = element.OwnerDocument.CreateElement("upnp", "actor", NS_UPNP);
- e.InnerText = actor.Name;
- element.AppendChild(e);
+ AddValue(element, "upnp", (actor.Type ?? PersonType.Actor).ToLower(), actor.Name, NS_UPNP);
}
}
private void AddBookmarkInfo(BaseItem item, User user, XmlElement element)
{
- //var bookmark = bookmarkable.Bookmark;
- //if (bookmark.HasValue)
- //{
- // var dcmInfo = item.OwnerDocument.CreateElement("sec", "dcmInfo", NS_SEC);
- // dcmInfo.InnerText = string.Format("BM={0}", bookmark.Value);
- // item.AppendChild(dcmInfo);
- //}
+ var userdata = _userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+
+ if (userdata.PlaybackPositionTicks > 0)
+ {
+ var dcmInfo = element.OwnerDocument.CreateElement("sec", "dcmInfo", NS_SEC);
+ dcmInfo.InnerText = string.Format("BM={0}", Convert.ToInt32(TimeSpan.FromTicks(userdata.PlaybackPositionTicks).TotalSeconds).ToString(_usCulture));
+ element.AppendChild(dcmInfo);
+ }
}
- private void AddGeneralProperties(BaseItem item, XmlElement element)
+ /// <summary>
+ /// Adds fields used by both items and folders
+ /// </summary>
+ /// <param name="item"></param>
+ /// <param name="element"></param>
+ private void AddCommonFields(BaseItem item, XmlElement element)
{
- //var prop = string.Empty;
- //if (props.TryGetValue("DateO", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("dc", "date", NS_DC);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
- //if (props.TryGetValue("Genre", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "genre", NS_UPNP);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
+ if (item.PremiereDate.HasValue)
+ {
+ AddValue(element, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
+ }
+
+ if (item.Genres.Count > 0)
+ {
+ AddValue(element, "upnp", "genre", item.Genres[0], NS_UPNP);
+ }
+
+ if (item.Studios.Count > 0)
+ {
+ AddValue(element, "upnp", "publisher", item.Studios[0], NS_UPNP);
+ }
+
+ AddValue(element, "dc", "title", item.Name, NS_DC);
if (!string.IsNullOrWhiteSpace(item.Overview))
{
- var e = element.OwnerDocument.CreateElement("dc", "description", NS_DC);
- e.InnerText = item.Overview;
- element.AppendChild(e);
- }
-
- //if (props.TryGetValue("Artist", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "artist", NS_UPNP);
- // e.SetAttribute("role", "AlbumArtist");
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
- //if (props.TryGetValue("Performer", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "artist", NS_UPNP);
- // e.SetAttribute("role", "Performer");
- // e.InnerText = prop;
- // item.AppendChild(e);
- // e = item.OwnerDocument.CreateElement("dc", "creator", NS_DC);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
- //if (props.TryGetValue("Album", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "album", NS_UPNP);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
- //if (props.TryGetValue("Track", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "originalTrackNumber", NS_UPNP);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
- //if (props.TryGetValue("Creator", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("dc", "creator", NS_DC);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
-
- //if (props.TryGetValue("Director", out prop))
- //{
- // var e = item.OwnerDocument.CreateElement("upnp", "director", NS_UPNP);
- // e.InnerText = prop;
- // item.AppendChild(e);
- //}
+ AddValue(element, "dc", "description", item.Overview, NS_DC);
+ }
+
+ if (!string.IsNullOrEmpty(item.OfficialRating))
+ {
+ AddValue(element, "dc", "rating", item.OfficialRating, NS_DC);
+ }
+
+ AddPeople(item, element);
+ }
+
+ private void AddGeneralProperties(BaseItem item, XmlElement element)
+ {
+ AddCommonFields(item, element);
+
+ var audio = item as Audio;
+
+ if (audio != null)
+ {
+ if (audio.Artists.Count > 0)
+ {
+ AddValue(element, "upnp", "artist", audio.Artists[0], NS_UPNP);
+ }
+
+ if (!string.IsNullOrEmpty(audio.Album))
+ {
+ AddValue(element, "upnp", "album", audio.Album, NS_UPNP);
+ }
+
+ if (!string.IsNullOrEmpty(audio.AlbumArtist))
+ {
+ AddValue(element, "upnp", "albumArtist", audio.AlbumArtist, NS_UPNP);
+ }
+ }
+
+ var album = item as MusicAlbum;
+
+ if (album != null)
+ {
+ if (!string.IsNullOrEmpty(album.AlbumArtist))
+ {
+ AddValue(element, "upnp", "artist", album.AlbumArtist, NS_UPNP);
+ AddValue(element, "upnp", "albumArtist", album.AlbumArtist, NS_UPNP);
+ }
+ }
+
+ var musicVideo = item as MusicVideo;
+
+ if (musicVideo != null)
+ {
+ if (!string.IsNullOrEmpty(musicVideo.Artist))
+ {
+ AddValue(element, "upnp", "artist", musicVideo.Artist, NS_UPNP);
+ }
+
+ if (!string.IsNullOrEmpty(musicVideo.Album))
+ {
+ AddValue(element, "upnp", "album", musicVideo.Album, NS_UPNP);
+ }
+ }
+
+ if (item.IndexNumber.HasValue)
+ {
+ AddValue(element, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
+ }
}
private void AddCover(BaseItem item, XmlElement element)
{
- //var result = item.OwnerDocument;
- //var cover = resource as IMediaCover;
- //if (cover == null)
- //{
- // return;
- //}
- //try
- //{
- // var c = cover.Cover;
- // var curl = String.Format(
- // "http://{0}:{1}{2}cover/{3}",
- // request.LocalEndPoint.Address,
- // request.LocalEndPoint.Port,
- // prefix,
- // resource.Id
- // );
- // var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
- // var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
- // profile.InnerText = "JPEG_TN";
- // icon.SetAttributeNode(profile);
- // icon.InnerText = curl;
- // item.AppendChild(icon);
- // icon = result.CreateElement("upnp", "icon", NS_UPNP);
- // profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
- // profile.InnerText = "JPEG_TN";
- // icon.SetAttributeNode(profile);
- // icon.InnerText = curl;
- // item.AppendChild(icon);
-
- // var res = result.CreateElement(string.Empty, "res", NS_DIDL);
- // res.InnerText = curl;
-
- // res.SetAttribute("protocolInfo", string.Format(
- // "http-get:*:{1}:{0};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}",
- // c.PN, DlnaMaps.Mime[c.Type], DlnaMaps.DefaultStreaming
- // ));
- // var width = c.MetaWidth;
- // var height = c.MetaHeight;
- // if (width.HasValue && height.HasValue)
- // {
- // res.SetAttribute("resolution", string.Format("{0}x{1}", width.Value, height.Value));
- // }
- // else
- // {
- // res.SetAttribute("resolution", "200x200");
- // }
- // res.SetAttribute("protocolInfo", string.Format(
- // "http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=01;DLNA.ORG_CI=1;DLNA.ORG_FLAGS={0}",
- // DlnaMaps.DefaultInteractive
- // ));
- // item.AppendChild(res);
- //}
- //catch (Exception)
- //{
- // return;
- //}
+ var imageInfo = GetImageInfo(item);
+
+ if (imageInfo == null)
+ {
+ return;
+ }
+
+ var result = element.OwnerDocument;
+
+ var curl = GetImageUrl(imageInfo);
+
+ var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
+ var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
+ profile.InnerText = "JPEG_TN";
+ icon.SetAttributeNode(profile);
+ icon.InnerText = curl;
+ element.AppendChild(icon);
+
+ icon = result.CreateElement("upnp", "icon", NS_UPNP);
+ profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
+ profile.InnerText = "JPEG_TN";
+ icon.SetAttributeNode(profile);
+ icon.InnerText = curl;
+ element.AppendChild(icon);
+
+ if (!_profile.EnableAlbumArtInDidl)
+ {
+ return;
+ }
+
+ var res = result.CreateElement(string.Empty, "res", NS_DIDL);
+ res.InnerText = curl;
+
+ int? width = imageInfo.Width;
+ int? height = imageInfo.Height;
+
+ var mediaProfile = new MediaFormatProfileResolver().ResolveImageFormat("jpg", width, height);
+
+ res.SetAttribute("protocolInfo", string.Format(
+ "http-get:*:{1}DLNA.ORG_PN=:{0};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}",
+ mediaProfile, "image/jpeg", DlnaMaps.DefaultStreaming
+ ));
+
+ if (width.HasValue && height.HasValue)
+ {
+ res.SetAttribute("resolution", string.Format("{0}x{1}", width.Value, height.Value));
+ }
+ else
+ {
+ // TODO: Devices need to see something here?
+ res.SetAttribute("resolution", "200x200");
+ }
+
+ element.AppendChild(res);
+ }
+
+ private ImageDownloadInfo GetImageInfo(BaseItem item)
+ {
+ if (item.HasImage(ImageType.Primary))
+ {
+ return GetImageInfo(item, ImageType.Primary);
+ }
+ if (item.HasImage(ImageType.Thumb))
+ {
+ return GetImageInfo(item, ImageType.Thumb);
+ }
+
+ if (item is Audio || item is Episode)
+ {
+ item = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary));
+
+ if (item != null)
+ {
+ return GetImageInfo(item, ImageType.Primary);
+ }
+ }
+
+ return null;
+ }
+
+ private ImageDownloadInfo GetImageInfo(BaseItem item, ImageType type)
+ {
+ var imageInfo = item.GetImageInfo(type, 0);
+ string tag = null;
+
+ try
+ {
+ var guid = _imageProcessor.GetImageCacheTag(item, ImageType.Primary);
+
+ tag = guid.HasValue ? guid.Value.ToString("N") : null;
+ }
+ catch
+ {
+
+ }
+
+ int? width = null;
+ int? height = null;
+
+ try
+ {
+ var size = _imageProcessor.GetImageSize(imageInfo.Path, imageInfo.DateModified);
+
+ width = Convert.ToInt32(size.Width);
+ height = Convert.ToInt32(size.Height);
+ }
+ catch
+ {
+
+ }
+
+ return new ImageDownloadInfo
+ {
+ ItemId = item.Id.ToString("N"),
+ Type = ImageType.Primary,
+ ImageTag = tag,
+ Width = width,
+ Height = height
+ };
+ }
+
+ class ImageDownloadInfo
+ {
+ internal string ItemId;
+ internal string ImageTag;
+ internal ImageType Type;
+
+ internal int? Width;
+ internal int? Height;
+ }
+
+ private string GetImageUrl(ImageDownloadInfo info)
+ {
+ return string.Format("{0}/Items/{1}/Images/{2}?tag={3}&format=jpg",
+ _serverAddress,
+ info.ItemId,
+ info.Type,
+ info.ImageTag);
}
}
}
diff --git a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
index ee7fae6f93..33286a474d 100644
--- a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
@@ -176,7 +176,7 @@ namespace MediaBrowser.Dlna.Server
ServiceType = "urn:schemas-upnp-org:service:ContentDirectory:1",
ServiceId = "urn:upnp-org:serviceId:ContentDirectory",
ScpdUrl = "/mediabrowser/dlna/contentdirectory.xml",
- ControlUrl = "/mediabrowser/dlna/control"
+ ControlUrl = "/mediabrowser/dlna/" + _serverUdn + "/control"
});
return list;
diff --git a/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs b/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs
index 702aa6f995..050d89f496 100644
--- a/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs
+++ b/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common;
+using System.Linq;
+using MediaBrowser.Common;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@@ -18,8 +19,12 @@ namespace MediaBrowser.Dlna.Server
private readonly IApplicationHost _appHost;
private readonly INetworkManager _network;
+ public static DlnaServerEntryPoint Instance;
+
public DlnaServerEntryPoint(IServerConfigurationManager config, ILogManager logManager, IApplicationHost appHost, INetworkManager network)
{
+ Instance = this;
+
_config = config;
_appHost = appHost;
_network = network;
@@ -86,6 +91,11 @@ namespace MediaBrowser.Dlna.Server
}
}
+ public UpnpDevice GetServerUpnpDevice(string uuid)
+ {
+ return _ssdpHandler.Devices.FirstOrDefault(i => string.Equals(uuid, i.Uuid.ToString("N"), StringComparison.OrdinalIgnoreCase));
+ }
+
private void DisposeServer()
{
lock (_syncLock)
diff --git a/MediaBrowser.Dlna/Server/SsdpHandler.cs b/MediaBrowser.Dlna/Server/SsdpHandler.cs
index c908eb4a8e..0c3e6c735b 100644
--- a/MediaBrowser.Dlna/Server/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Server/SsdpHandler.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.Dlna.Server
Start();
}
- private IEnumerable<UpnpDevice> Devices
+ public IEnumerable<UpnpDevice> Devices
{
get
{