diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs new file mode 100644 index 0000000000..922c67aa2d --- /dev/null +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -0,0 +1,89 @@ +using MediaBrowser.Controller.Dlna; +using ServiceStack; +using ServiceStack.Web; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Dlna +{ + [Route("/Dlna/{UuId}/description.xml", "GET", Summary = "Gets dlna server info")] + [Route("/Dlna/{UuId}/description", "GET", Summary = "Gets dlna server info")] + public class GetDescriptionXml + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")] + [Route("/Dlna/{UuId}/contentdirectory", "GET", Summary = "Gets the content directory xml")] + public class GetContentDirectory + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/control", "POST", Summary = "Processes a control request")] + public class ProcessControlRequest : IRequiresRequestStream + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + + public Stream RequestStream { get; set; } + } + + public class DlnaServerService : BaseApiService + { + private readonly IDlnaManager _dlnaManager; + + public DlnaServerService(IDlnaManager dlnaManager) + { + _dlnaManager = dlnaManager; + } + + public object Get(GetDescriptionXml request) + { + var xml = _dlnaManager.GetServerDescriptionXml(GetRequestHeaders(), request.UuId); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Get(GetContentDirectory request) + { + var xml = _dlnaManager.GetContentDirectoryXml(GetRequestHeaders()); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Post(ProcessControlRequest request) + { + var response = PostAsync(request).Result; + + return ResultFactory.GetResult(response.Xml, "text/xml"); + } + + private async Task PostAsync(ProcessControlRequest request) + { + using (var reader = new StreamReader(request.RequestStream)) + { + return _dlnaManager.ProcessControlRequest(new ControlRequest + { + Headers = GetRequestHeaders(), + InputXml = await reader.ReadToEndAsync().ConfigureAwait(false) + }); + } + } + + private IDictionary GetRequestHeaders() + { + var headers = new Dictionary(); + + foreach (var key in Request.Headers.AllKeys) + { + headers[key] = Request.Headers[key]; + } + + return headers; + } + } +} diff --git a/MediaBrowser.Api/DlnaService.cs b/MediaBrowser.Api/Dlna/DlnaService.cs similarity index 98% rename from MediaBrowser.Api/DlnaService.cs rename to MediaBrowser.Api/Dlna/DlnaService.cs index 792a7ff43f..9e6ca3aea9 100644 --- a/MediaBrowser.Api/DlnaService.cs +++ b/MediaBrowser.Api/Dlna/DlnaService.cs @@ -4,7 +4,7 @@ using ServiceStack; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Dlna { [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")] public class GetProfileInfos : IReturn> diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 6667ba25c6..967bc1fbac 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Api.Library public string Id { get; set; } } - [Route("/Videos/{Id}/Subtitle/{Index}", "GET")] + [Route("/Videos/{Id}/Subtitles/{Index}", "GET")] [Api(Description = "Gets an external subtitle file")] public class GetSubtitle { diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index c03eddf99e..edbae3903e 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,7 +66,8 @@ Properties\SharedVersion.cs - + + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bb55b893a2..e588068d0d 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -185,9 +185,9 @@ namespace MediaBrowser.Api.Playback { var args = string.Empty; - if (state.IsRemote || !state.HasMediaStreams) + if (!state.HasMediaStreams) { - return string.Empty; + return state.IsInputVideo ? "-sn" : string.Empty; } if (state.VideoStream != null) @@ -1341,6 +1341,12 @@ namespace MediaBrowser.Api.Playback RequestedUrl = url }; + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) + { + state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(); + } + var item = string.IsNullOrEmpty(request.MediaSourceId) ? DtoService.GetItemByDtoId(request.Id) : DtoService.GetItemByDtoId(request.MediaSourceId); @@ -1487,33 +1493,27 @@ namespace MediaBrowser.Api.Playback if (videoRequest != null) { - if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream, state.VideoType)) + if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream)) { videoRequest.VideoCodec = "copy"; } - //if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream)) - //{ - // request.AudioCodec = "copy"; - //} + if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream, state.SupportedAudioCodecs)) + { + request.AudioCodec = "copy"; + } } return state; } - private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream, VideoType videoType) + private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) { if (videoStream.IsInterlaced) { return false; } - // Not going to attempt this with folder rips - if (videoType != VideoType.VideoFile) - { - return false; - } - // Source and target codecs must match if (!string.Equals(request.VideoCodec, videoStream.Codec, StringComparison.OrdinalIgnoreCase)) { @@ -1584,13 +1584,13 @@ namespace MediaBrowser.Api.Playback } } - return SupportsAutomaticVideoStreamCopy; + return request.EnableAutoStreamCopy; } - private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream) + private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream, List supportedAudioCodecs) { // Source and target codecs must match - if (string.IsNullOrEmpty(request.AudioCodec) || !string.Equals(request.AudioCodec, audioStream.Codec, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } @@ -1623,15 +1623,7 @@ namespace MediaBrowser.Api.Playback } } - return SupportsAutomaticVideoStreamCopy; - } - - protected virtual bool SupportsAutomaticVideoStreamCopy - { - get - { - return false; - } + return true; } private void ApplyDeviceProfileSettings(StreamState state) diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 6e71e503f3..b5cd1bd409 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -24,7 +24,8 @@ namespace MediaBrowser.Api.Playback.Hls /// public abstract class BaseHlsService : BaseStreamingService { - protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) + protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) + : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { } @@ -77,6 +78,7 @@ namespace MediaBrowser.Api.Playback.Hls return ProcessRequestAsync(request).Result; } + private static readonly SemaphoreSlim FfmpegStartLock = new SemaphoreSlim(1, 1); /// /// Processes the request async. /// @@ -103,31 +105,40 @@ namespace MediaBrowser.Api.Playback.Hls } var playlist = GetOutputFilePath(state); - var isPlaylistNewlyCreated = false; - // If the playlist doesn't already exist, startup ffmpeg - if (!File.Exists(playlist)) - { - isPlaylistNewlyCreated = true; - - try - { - await StartFfMpeg(state, playlist).ConfigureAwait(false); - } - catch - { - state.Dispose(); - throw; - } - } - else + if (File.Exists(playlist)) { ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls); } - - if (isPlaylistNewlyCreated) + else { - await WaitForMinimumSegmentCount(playlist, GetSegmentWait()).ConfigureAwait(false); + await FfmpegStartLock.WaitAsync().ConfigureAwait(false); + try + { + if (File.Exists(playlist)) + { + ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls); + } + else + { + // If the playlist doesn't already exist, startup ffmpeg + try + { + await StartFfMpeg(state, playlist).ConfigureAwait(false); + } + catch + { + state.Dispose(); + throw; + } + } + + await WaitForMinimumSegmentCount(playlist, GetSegmentWait()).ConfigureAwait(false); + } + finally + { + FfmpegStartLock.Release(); + } } int audioBitrate; @@ -295,7 +306,7 @@ namespace MediaBrowser.Api.Playback.Hls // If performSubtitleConversions is true we're actually starting ffmpeg var startNumberParam = performSubtitleConversions ? GetStartNumber(state).ToString(UsCulture) : "0"; - + var args = string.Format("{0} {1} -i {2}{3} -map_metadata -1 -threads {4} {5} {6} -sc_threshold 0 {7} -hls_time {8} -start_number {9} -hls_list_size {10} \"{11}\"", itsOffset, inputModifier, diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index bedf742c2c..1bca4cae9a 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -98,14 +98,6 @@ namespace MediaBrowser.Api.Playback.Hls ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls); } - protected override bool SupportsAutomaticVideoStreamCopy - { - get - { - return true; - } - } - /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index add517b5da..d5355783e8 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -171,5 +171,13 @@ namespace MediaBrowser.Api.Playback return Width.HasValue || Height.HasValue; } } + + [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool EnableAutoStreamCopy { get; set; } + + public VideoStreamRequest() + { + EnableAutoStreamCopy = true; + } } } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ce7d79917a..e41f296638 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -67,10 +67,13 @@ namespace MediaBrowser.Api.Playback public string AudioSync = "1"; public string VideoSync = "vfr"; + public List SupportedAudioCodecs { get; set; } + public StreamState(ILiveTvManager liveTvManager, ILogger logger) { _liveTvManager = liveTvManager; _logger = logger; + SupportedAudioCodecs = new List(); } public string InputAudioSync { get; set; } diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index 5c1c716417..b71cf67b66 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; using ServiceStack; @@ -32,10 +31,10 @@ namespace MediaBrowser.Api } /// - /// Class BrowseTo + /// Class DisplayContent /// [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")] - public class BrowseTo : IReturnVoid + public class DisplayContent : IReturnVoid { /// /// Gets or sets the id. @@ -218,6 +217,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } } + [Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")] [Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")] public class PostCapabilities : IReturnVoid { @@ -226,7 +226,7 @@ namespace MediaBrowser.Api /// /// The id. [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public Guid Id { get; set; } + public string Id { get; set; } [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Game, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public string PlayableMediaTypes { get; set; } @@ -307,7 +307,7 @@ namespace MediaBrowser.Api /// Posts the specified request. /// /// The request. - public void Post(BrowseTo request) + public void Post(DisplayContent request) { var command = new BrowseRequest { @@ -421,7 +421,11 @@ namespace MediaBrowser.Api public void Post(PostCapabilities request) { - _sessionManager.ReportCapabilities(request.Id, new SessionCapabilities + if (string.IsNullOrWhiteSpace(request.Id)) + { + request.Id = GetSession().Id.ToString("N"); + } + _sessionManager.ReportCapabilities(new Guid(request.Id), new SessionCapabilities { PlayableMediaTypes = request.PlayableMediaTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index ac6b9290ef..e15c32518e 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -15,6 +15,44 @@ namespace MediaBrowser.Common.Implementations.Networking /// /// IPAddress. public IEnumerable GetLocalIpAddresses() + { + var list = GetIPsDefault().Where(i => !IPAddress.IsLoopback(i)).Select(i => i.ToString()).ToList(); + + if (list.Count > 0) + { + return list; + } + + return GetLocalIpAddressesFallback(); + } + + private IEnumerable GetIPsDefault() + { + foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) + { + var props = adapter.GetIPProperties(); + var gateways = from ga in props.GatewayAddresses + where !ga.Address.Equals(IPAddress.Any) + select true; + + if (!gateways.Any()) + { + continue; + } + + foreach (var uni in props.UnicastAddresses) + { + var address = uni.Address; + if (address.AddressFamily != AddressFamily.InterNetwork) + { + continue; + } + yield return address; + } + } + } + + private IEnumerable GetLocalIpAddressesFallback() { var host = Dns.GetHostEntry(Dns.GetHostName()); @@ -25,7 +63,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => i.ToString()) .Reverse(); } - + /// /// Gets a random port number that is currently available /// @@ -50,6 +88,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes())) .FirstOrDefault(); } + /// /// Parses the specified endpointstring. /// diff --git a/MediaBrowser.Controller/Dlna/ControlRequest.cs b/MediaBrowser.Controller/Dlna/ControlRequest.cs new file mode 100644 index 0000000000..74e68b7d01 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/ControlRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Dlna +{ + public class ControlRequest + { + public IDictionary Headers { get; set; } + + public string InputXml { get; set; } + + public ControlRequest() + { + Headers = new Dictionary(); + } + } + + public class ControlResponse + { + public IDictionary Headers { get; set; } + + public string Xml { get; set; } + + public ControlResponse() + { + Headers = new Dictionary(); + } + } +} diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 521d17e01f..bcccaaa2e9 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -55,5 +55,27 @@ namespace MediaBrowser.Controller.Dlna /// The device information. /// DeviceProfile. DeviceProfile GetProfile(DeviceIdentification deviceInfo); + + /// + /// Gets the server description XML. + /// + /// The headers. + /// The server uu identifier. + /// System.String. + string GetServerDescriptionXml(IDictionary headers, string serverUuId); + + /// + /// Gets the content directory XML. + /// + /// The headers. + /// System.String. + string GetContentDirectoryXml(IDictionary headers); + + /// + /// Processes the control request. + /// + /// The request. + /// ControlResponse. + ControlResponse ProcessControlRequest(ControlRequest request); } } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 8eb6236d1a..0ca1ffde04 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class Audio /// - public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo, IHasSeries + public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo { public Audio() { @@ -51,15 +51,6 @@ namespace MediaBrowser.Controller.Entities.Audio } } - [IgnoreDataMember] - public string SeriesName - { - get - { - return Album; - } - } - /// /// Gets or sets the artist. /// diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index cce241542b..277ec8b782 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class MusicAlbum /// - public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasTags, IHasLookupInfo, IHasSeries + public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasTags, IHasLookupInfo { public List SoundtrackIds { get; set; } @@ -67,15 +67,6 @@ namespace MediaBrowser.Controller.Entities.Audio } } - [IgnoreDataMember] - public string SeriesName - { - get - { - return AlbumArtist; - } - } - /// /// Override this to true if class should be grouped under a container in indicies /// The container class should be defined via IndexContainer diff --git a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs index 8e1f94178d..019c9d31a5 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs @@ -1,4 +1,6 @@ - +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + namespace MediaBrowser.Controller.LiveTv { public class LiveStreamInfo @@ -20,5 +22,22 @@ namespace MediaBrowser.Controller.LiveTv /// /// The identifier. public string Id { get; set; } + + /// + /// Gets or sets the media container. + /// + /// The media container. + public string MediaContainer { get; set; } + + /// + /// Gets or sets the media streams. + /// + /// The media streams. + public List MediaStreams { get; set; } + + public LiveStreamInfo() + { + MediaStreams = new List(); + } } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 3082d12ca5..692a7a92eb 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -78,6 +78,7 @@ + diff --git a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs b/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs index 9c757503c0..8ca482b11d 100644 --- a/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs +++ b/MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs @@ -103,8 +103,9 @@ namespace MediaBrowser.Controller.Resolvers ".wav", ".ape", ".ogg", - ".oga" - + ".oga", + ".asf", + ".mp4" }; private static readonly Dictionary AudioFileExtensionsDictionary = AudioFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index 1d5fbf3590..d4612acb5a 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -35,14 +35,6 @@ namespace MediaBrowser.Controller.Session /// Task. Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken); - /// - /// Sends the browse command. - /// - /// The command. - /// The cancellation token. - /// Task. - Task SendBrowseCommand(BrowseRequest command, CancellationToken cancellationToken); - /// /// Sends the playstate command. /// @@ -96,6 +88,22 @@ namespace MediaBrowser.Controller.Session /// The cancellation token. /// Task. Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken); + + /// + /// Sends the playback start notification. + /// + /// The session information. + /// The cancellation token. + /// Task. + Task SendPlaybackStartNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken); + + /// + /// Sends the playback start notification. + /// + /// The session information. + /// The cancellation token. + /// Task. + Task SendPlaybackStoppedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken); /// /// Sends the server restart notification. diff --git a/MediaBrowser.Dlna/Common/Argument.cs b/MediaBrowser.Dlna/Common/Argument.cs new file mode 100644 index 0000000000..a3ff8ecc88 --- /dev/null +++ b/MediaBrowser.Dlna/Common/Argument.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Dlna.Common +{ + public class Argument + { + public string Name { get; set; } + + public string Direction { get; set; } + + public string RelatedStateVariable { get; set; } + } +} diff --git a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs b/MediaBrowser.Dlna/Common/DeviceIcon.cs similarity index 91% rename from MediaBrowser.Dlna/PlayTo/DeviceIcon.cs rename to MediaBrowser.Dlna/Common/DeviceIcon.cs index a46abdd745..bec10dcc5a 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs +++ b/MediaBrowser.Dlna/Common/DeviceIcon.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceIcon { diff --git a/MediaBrowser.Dlna/PlayTo/DeviceService.cs b/MediaBrowser.Dlna/Common/DeviceService.cs similarity index 52% rename from MediaBrowser.Dlna/PlayTo/DeviceService.cs rename to MediaBrowser.Dlna/Common/DeviceService.cs index 082128b225..8f8b175a42 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceService.cs +++ b/MediaBrowser.Dlna/Common/DeviceService.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceService { @@ -13,15 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo public string EventSubUrl { get; set; } - public DeviceService(string serviceType, string serviceId, string scpdUrl, string controlUrl, string eventSubUrl) - { - ServiceType = serviceType; - ServiceId = serviceId; - ScpdUrl = scpdUrl; - ControlUrl = controlUrl; - EventSubUrl = eventSubUrl; - } - public override string ToString() { return string.Format("{0}", ServiceId); diff --git a/MediaBrowser.Dlna/Common/ServiceAction.cs b/MediaBrowser.Dlna/Common/ServiceAction.cs new file mode 100644 index 0000000000..7685e217e8 --- /dev/null +++ b/MediaBrowser.Dlna/Common/ServiceAction.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class ServiceAction + { + public string Name { get; set; } + + public List ArgumentList { get; set; } + + public override string ToString() + { + return Name; + } + + public ServiceAction() + { + ArgumentList = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/Common/StateVariable.cs b/MediaBrowser.Dlna/Common/StateVariable.cs new file mode 100644 index 0000000000..21771e7b8e --- /dev/null +++ b/MediaBrowser.Dlna/Common/StateVariable.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class StateVariable + { + public string Name { get; set; } + + public string DataType { get; set; } + + public bool SendsEvents { get; set; } + + public List AllowedValues { get; set; } + + public override string ToString() + { + return Name; + } + + public StateVariable() + { + AllowedValues = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 7a8fd41830..624f23f7f2 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,9 +1,9 @@ -using System.Text; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; using MediaBrowser.Dlna.Profiles; +using MediaBrowser.Dlna.Server; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.RegularExpressions; namespace MediaBrowser.Dlna @@ -476,5 +477,26 @@ namespace MediaBrowser.Dlna internal DeviceProfileInfo Info { get; set; } internal string Path { get; set; } } + + public string GetServerDescriptionXml(IDictionary headers, string serverUuId) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new DescriptionXmlBuilder(profile, serverUuId).GetXml(); + } + + public string GetContentDirectoryXml(IDictionary headers) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new ContentDirectoryXmlBuilder(profile).GetXml(); + } + + public ControlResponse ProcessControlRequest(ControlRequest request) + { + return new ControlHandler(_logger).ProcessControlRequest(request); + } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/Images/logo-120.jpg b/MediaBrowser.Dlna/Images/logo-120.jpg new file mode 100644 index 0000000000..1de803c8fa Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-120.jpg differ diff --git a/MediaBrowser.Dlna/Images/logo-120.png b/MediaBrowser.Dlna/Images/logo-120.png new file mode 100644 index 0000000000..2dd04d4681 Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-120.png differ diff --git a/MediaBrowser.Dlna/Images/logo-48.jpg b/MediaBrowser.Dlna/Images/logo-48.jpg new file mode 100644 index 0000000000..f1e7302aae Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-48.jpg differ diff --git a/MediaBrowser.Dlna/Images/logo-48.png b/MediaBrowser.Dlna/Images/logo-48.png new file mode 100644 index 0000000000..3b13d141ce Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-48.png differ diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index d1fed45729..0980ee81db 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -52,13 +52,13 @@ Properties\SharedVersion.cs - + Code - + @@ -68,20 +68,25 @@ - + + + + + + - + - + @@ -141,6 +146,12 @@ + + + + + +