Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Tim Hobbs 2014-03-24 09:37:44 -07:00
commit 38a0af6e86
71 changed files with 4465 additions and 1642 deletions

View File

@ -10,8 +10,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetCultures
/// </summary>
[Route("/Localization/Cultures", "GET")]
[Api(Description = "Gets known cultures")]
[Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")]
public class GetCultures : IReturn<List<CultureDto>>
{
}
@ -19,8 +18,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetCountries
/// </summary>
[Route("/Localization/Countries", "GET")]
[Api(Description = "Gets known countries")]
[Route("/Localization/Countries", "GET", Summary = "Gets known countries")]
public class GetCountries : IReturn<List<CountryInfo>>
{
}
@ -28,8 +26,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class ParentalRatings
/// </summary>
[Route("/Localization/ParentalRatings", "GET")]
[Api(Description = "Gets known parental ratings")]
[Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")]
public class GetParentalRatings : IReturn<List<ParentalRating>>
{
}

View File

@ -117,10 +117,9 @@ namespace MediaBrowser.Api.Movies
public object Get(GetMovieRecommendations request)
{
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
var user = _userManager.GetUserById(request.UserId.Value);
var folder = user.RootFolder;
var movies = folder.RecursiveChildren.OfType<Movie>().ToList();
var movies = user.RootFolder.GetRecursiveChildren(user).OfType<Movie>().ToList();
var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());

View File

@ -5,8 +5,7 @@ using ServiceStack;
namespace MediaBrowser.Api
{
[Route("/News/Product", "GET")]
[Api(Description = "Gets the latest product news.")]
[Route("/News/Product", "GET", Summary = "Gets the latest product news.")]
public class GetProductNews : IReturn<QueryResult<NewsItem>>
{
/// <summary>

View File

@ -1,15 +1,14 @@
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Model.Notifications;
using ServiceStack;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ServiceStack;
namespace MediaBrowser.Api
{
[Route("/Notifications/{UserId}", "GET")]
[Api(Description = "Gets notifications")]
[Route("/Notifications/{UserId}", "GET", Summary = "Gets notifications")]
public class GetNotifications : IReturn<NotificationResult>
{
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
@ -25,16 +24,14 @@ namespace MediaBrowser.Api
public int? Limit { get; set; }
}
[Route("/Notifications/{UserId}/Summary", "GET")]
[Api(Description = "Gets a notification summary for a user")]
[Route("/Notifications/{UserId}/Summary", "GET", Summary = "Gets a notification summary for a user")]
public class GetNotificationsSummary : IReturn<NotificationsSummary>
{
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public Guid UserId { get; set; }
}
[Route("/Notifications/{UserId}", "POST")]
[Api(Description = "Adds a notifications")]
[Route("/Notifications/{UserId}", "POST", Summary = "Adds a notifications")]
public class AddUserNotification : IReturn<Notification>
{
[ApiMember(Name = "Id", Description = "The Id of the new notification. If unspecified one will be provided.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
@ -62,8 +59,7 @@ namespace MediaBrowser.Api
public NotificationLevel Level { get; set; }
}
[Route("/Notifications/{UserId}/Read", "POST")]
[Api(Description = "Marks notifications as read")]
[Route("/Notifications/{UserId}/Read", "POST", Summary = "Marks notifications as read")]
public class MarkRead : IReturnVoid
{
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -73,8 +69,7 @@ namespace MediaBrowser.Api
public string Ids { get; set; }
}
[Route("/Notifications/{UserId}/Unread", "POST")]
[Api(Description = "Marks notifications as unread")]
[Route("/Notifications/{UserId}/Unread", "POST", Summary = "Marks notifications as unread")]
public class MarkUnread : IReturnVoid
{
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]

View File

@ -1,21 +1,20 @@
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Constants;
using MediaBrowser.Common.Constants;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Serialization;
using ServiceStack;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api
{
/// <summary>
/// Class InstallPackage
/// </summary>
[Route("/PackageReviews/{Id}", "POST")]
[Api(("Creates or updates a package review"))]
[Route("/Packages/Reviews/{Id}", "POST", Summary = "Creates or updates a package review")]
public class CreateReviewRequest : IReturnVoid
{
/// <summary>
@ -57,8 +56,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class InstallPackage
/// </summary>
[Route("/PackageReviews/{Id}", "GET")]
[Api(("Retrieve reviews for a package"))]
[Route("/Packages/{Id}/Reviews", "GET", Summary = "Gets reviews for a package")]
public class ReviewRequest : IReturn<List<PackageReviewInfo>>
{
/// <summary>

View File

@ -14,8 +14,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetPackage
/// </summary>
[Route("/Packages/{Name}", "GET")]
[Api(("Gets a package, by name or assembly guid"))]
[Route("/Packages/{Name}", "GET", Summary = "Gets a package, by name or assembly guid")]
public class GetPackage : IReturn<PackageInfo>
{
/// <summary>
@ -36,8 +35,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetPackages
/// </summary>
[Route("/Packages", "GET")]
[Api(("Gets available packages"))]
[Route("/Packages", "GET", Summary = "Gets available packages")]
public class GetPackages : IReturn<List<PackageInfo>>
{
/// <summary>
@ -57,8 +55,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetPackageVersionUpdates
/// </summary>
[Route("/Packages/Updates", "GET")]
[Api(("Gets available package updates for currently installed packages"))]
[Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")]
public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>>
{
/// <summary>
@ -72,8 +69,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class InstallPackage
/// </summary>
[Route("/Packages/Installed/{Name}", "POST")]
[Api(("Installs a package"))]
[Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")]
public class InstallPackage : IReturnVoid
{
/// <summary>
@ -108,8 +104,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class CancelPackageInstallation
/// </summary>
[Route("/Packages/Installing/{Id}", "DELETE")]
[Api(("Cancels a package installation"))]
[Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")]
public class CancelPackageInstallation : IReturnVoid
{
/// <summary>

View File

@ -9,7 +9,6 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Library;
@ -735,14 +734,21 @@ namespace MediaBrowser.Api.Playback
{
if (audioStream != null)
{
if (audioStream.Channels > 2 && request.AudioCodec.HasValue)
{
if (request.AudioCodec.Value == AudioCodecs.Wma)
if (audioStream.Channels > 2 && string.Equals(request.AudioCodec, "wma", StringComparison.OrdinalIgnoreCase))
{
// wmav2 currently only supports two channel output
return 2;
}
}
if (request.MaxAudioChannels.HasValue)
{
if (audioStream != null && audioStream.Channels.HasValue)
{
return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
}
return request.MaxAudioChannels.Value;
}
return request.AudioChannels;
@ -768,26 +774,26 @@ namespace MediaBrowser.Api.Playback
{
var codec = request.AudioCodec;
if (codec.HasValue)
if (!string.IsNullOrEmpty(codec))
{
if (codec == AudioCodecs.Aac)
if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase))
{
return "aac -strict experimental";
}
if (codec == AudioCodecs.Mp3)
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
{
return "libmp3lame";
}
if (codec == AudioCodecs.Vorbis)
if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
{
return "libvorbis";
}
if (codec == AudioCodecs.Wma)
if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
{
return "wmav2";
}
return codec.ToString().ToLower();
return codec.ToLower();
}
return "copy";
@ -802,26 +808,26 @@ namespace MediaBrowser.Api.Playback
{
var codec = request.VideoCodec;
if (codec.HasValue)
if (!string.IsNullOrEmpty(codec))
{
if (codec == VideoCodecs.H264)
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
{
return "libx264";
}
if (codec == VideoCodecs.Vpx)
if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
{
return "libvpx";
}
if (codec == VideoCodecs.Wmv)
if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
{
return "msmpeg4";
}
if (codec == VideoCodecs.Theora)
if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
{
return "libtheora";
}
return codec.ToString().ToLower();
return codec.ToLower();
}
return "copy";
@ -1201,77 +1207,81 @@ namespace MediaBrowser.Api.Playback
if (i == 0)
{
request.DeviceId = val;
// Device profile name
}
else if (i == 1)
{
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
request.DeviceId = val;
}
else if (i == 2)
{
if (videoRequest != null)
{
videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
}
request.MediaSourceId = val;
}
else if (i == 3)
{
request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true);
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
else if (i == 4)
{
if (videoRequest != null)
{
videoRequest.VideoCodec = val;
}
}
else if (i == 5)
{
request.AudioCodec = val;
}
else if (i == 6)
{
if (videoRequest != null)
{
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
}
}
else if (i == 5)
else if (i == 7)
{
if (videoRequest != null)
{
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
}
}
else if (i == 6)
else if (i == 8)
{
if (videoRequest != null)
{
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
}
}
else if (i == 7)
else if (i == 9)
{
request.AudioBitRate = int.Parse(val, UsCulture);
}
else if (i == 8)
else if (i == 10)
{
request.AudioChannels = int.Parse(val, UsCulture);
request.MaxAudioChannels = int.Parse(val, UsCulture);
}
else if (i == 9)
else if (i == 11)
{
if (videoRequest != null)
{
request.StartTimeTicks = long.Parse(val, UsCulture);
}
}
else if (i == 10)
else if (i == 12)
{
if (videoRequest != null)
{
videoRequest.Profile = val;
}
}
else if (i == 11)
else if (i == 13)
{
if (videoRequest != null)
{
videoRequest.Level = val;
}
}
else if (i == 12)
{
request.ForcedMimeType = val;
}
}
}
@ -1297,7 +1307,7 @@ namespace MediaBrowser.Api.Playback
var url = Request.PathInfo;
if (!request.AudioCodec.HasValue)
if (string.IsNullOrEmpty(request.AudioCodec))
{
request.AudioCodec = InferAudioCodec(url);
}
@ -1425,7 +1435,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
if (!videoRequest.VideoCodec.HasValue)
if (string.IsNullOrEmpty(videoRequest.VideoCodec))
{
videoRequest.VideoCodec = InferVideoCodec(url);
}
@ -1532,41 +1542,41 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>System.Nullable{AudioCodecs}.</returns>
private AudioCodecs? InferAudioCodec(string url)
private string InferAudioCodec(string url)
{
var ext = Path.GetExtension(url);
if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Mp3;
return "mp3";
}
if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Aac;
return "aac";
}
if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Wma;
return "wma";
}
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Vorbis;
return "vorbis";
}
if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Vorbis;
return "vorbis";
}
if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Vorbis;
return "vorbis";
}
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Vorbis;
return "vorbis";
}
if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
{
return AudioCodecs.Vorbis;
return "vorbis";
}
return null;
@ -1577,28 +1587,28 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>System.Nullable{VideoCodecs}.</returns>
private VideoCodecs? InferVideoCodec(string url)
private string InferVideoCodec(string url)
{
var ext = Path.GetExtension(url);
if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
{
return VideoCodecs.Wmv;
return "wmv";
}
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
{
return VideoCodecs.Vpx;
return "vpx";
}
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
{
return VideoCodecs.Theora;
return "theora";
}
if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
{
return VideoCodecs.H264;
return "h264";
}
return VideoCodecs.Copy;
return "copy";
}
}
}

View File

@ -91,11 +91,11 @@ namespace MediaBrowser.Api.Playback.Hls
{
var state = GetState(request, CancellationToken.None).Result;
if (!state.VideoRequest.VideoBitRate.HasValue && (!state.VideoRequest.VideoCodec.HasValue || state.VideoRequest.VideoCodec.Value != VideoCodecs.Copy))
if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException("A video bitrate is required");
}
if (!state.Request.AudioBitRate.HasValue && (!state.Request.AudioCodec.HasValue || state.Request.AudioCodec.Value != AudioCodecs.Copy))
if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException("An audio bitrate is required");
}

View File

@ -136,11 +136,11 @@ namespace MediaBrowser.Api.Playback.Hls
{
var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
if (!state.VideoRequest.VideoBitRate.HasValue && (!state.VideoRequest.VideoCodec.HasValue || state.VideoRequest.VideoCodec.Value != VideoCodecs.Copy))
if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException("A video bitrate is required");
}
if (!state.Request.AudioBitRate.HasValue && (!state.Request.AudioCodec.HasValue || state.Request.AudioCodec.Value != AudioCodecs.Copy))
if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException("An audio bitrate is required");
}

View File

@ -50,38 +50,48 @@ namespace MediaBrowser.Api.Playback.Progressive
var videoRequest = state.Request as VideoStreamRequest;
// Try to infer based on the desired video codec
if (videoRequest != null && videoRequest.VideoCodec.HasValue)
if (videoRequest != null && !string.IsNullOrEmpty(videoRequest.VideoCodec))
{
if (state.IsInputVideo)
{
switch (videoRequest.VideoCodec.Value)
if (string.Equals(videoRequest.VideoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
case VideoCodecs.H264:
return ".ts";
case VideoCodecs.Theora:
}
if (string.Equals(videoRequest.VideoCodec, "theora", StringComparison.OrdinalIgnoreCase))
{
return ".ogv";
case VideoCodecs.Vpx:
}
if (string.Equals(videoRequest.VideoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
{
return ".webm";
case VideoCodecs.Wmv:
}
if (string.Equals(videoRequest.VideoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
{
return ".asf";
}
}
}
// Try to infer based on the desired audio codec
if (state.Request.AudioCodec.HasValue)
if (!string.IsNullOrEmpty(state.Request.AudioCodec))
{
if (!state.IsInputVideo)
{
switch (state.Request.AudioCodec.Value)
if (string.Equals("aac", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
{
case AudioCodecs.Aac:
return ".aac";
case AudioCodecs.Mp3:
}
if (string.Equals("mp3", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
{
return ".mp3";
case AudioCodecs.Vorbis:
}
if (string.Equals("vorbis", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
{
return ".ogg";
case AudioCodecs.Wma:
}
if (string.Equals("wma", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
{
return ".wma";
}
}

View File

@ -1,5 +1,4 @@
using MediaBrowser.Model.Dto;
using ServiceStack;
using ServiceStack;
namespace MediaBrowser.Api.Playback
{
@ -26,7 +25,7 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <value>The audio codec.</value>
[ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public AudioCodecs? AudioCodec { get; set; }
public string AudioCodec { get; set; }
/// <summary>
/// Gets or sets the start time ticks.
@ -49,6 +48,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? AudioChannels { get; set; }
[ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MaxAudioChannels { get; set; }
/// <summary>
/// Gets or sets the audio sample rate.
/// </summary>
@ -69,8 +71,6 @@ namespace MediaBrowser.Api.Playback
public bool ThrowDebugError { get; set; }
public string Params { get; set; }
public string ForcedMimeType { get; set; }
}
public class VideoStreamRequest : StreamRequest
@ -80,7 +80,7 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <value>The video codec.</value>
[ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public VideoCodecs? VideoCodec { get; set; }
public string VideoCodec { get; set; }
/// <summary>
/// Gets or sets the video bit rate.

View File

@ -79,16 +79,6 @@ namespace MediaBrowser.Api.Playback
public string GetMimeType(string outputPath)
{
if (!string.IsNullOrWhiteSpace(Request.ForcedMimeType))
{
if (VideoRequest == null)
{
return "audio/" + Request.ForcedMimeType;
}
return "video/" + Request.ForcedMimeType;
}
return MimeTypes.GetMimeType(outputPath);
}
}

View File

@ -18,8 +18,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class Plugins
/// </summary>
[Route("/Plugins", "GET")]
[Api(("Gets a list of currently installed plugins"))]
[Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
public class GetPlugins : IReturn<List<PluginInfo>>
{
}
@ -27,8 +26,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UninstallPlugin
/// </summary>
[Route("/Plugins/{Id}", "DELETE")]
[Api(("Uninstalls a plugin"))]
[Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")]
public class UninstallPlugin : IReturnVoid
{
/// <summary>
@ -42,8 +40,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetPluginConfiguration
/// </summary>
[Route("/Plugins/{Id}/Configuration", "GET")]
[Api(("Gets a plugin's configuration"))]
[Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")]
public class GetPluginConfiguration
{
/// <summary>
@ -57,8 +54,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdatePluginConfiguration
/// </summary>
[Route("/Plugins/{Id}/Configuration", "POST")]
[Api(("Updates a plugin's configuration"))]
[Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")]
public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid
{
/// <summary>
@ -78,8 +74,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetPluginSecurityInfo
/// </summary>
[Route("/Plugins/SecurityInfo", "GET")]
[Api(("Gets plugin registration information"))]
[Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information")]
public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo>
{
}
@ -87,14 +82,12 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdatePluginSecurityInfo
/// </summary>
[Route("/Plugins/SecurityInfo", "POST")]
[Api("Updates plugin registration information")]
[Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information")]
public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid
{
}
[Route("/Plugins/RegistrationRecords/{Name}", "GET")]
[Api("Gets registration status for a feature")]
[Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature")]
public class GetRegistrationStatus
{
[ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]

View File

@ -39,6 +39,8 @@ namespace MediaBrowser.Api.ScheduledTasks
TaskManager = taskManager;
}
private bool _lastResponseHadTasksRunning = true;
/// <summary>
/// Gets the data to send.
/// </summary>
@ -46,7 +48,25 @@ namespace MediaBrowser.Api.ScheduledTasks
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(object state)
{
return Task.FromResult(TaskManager.ScheduledTasks
var tasks = TaskManager.ScheduledTasks.ToList();
var anyRunning = tasks.Any(i => i.State != TaskState.Idle);
if (anyRunning)
{
_lastResponseHadTasksRunning = true;
}
else
{
if (!_lastResponseHadTasksRunning)
{
return Task.FromResult<IEnumerable<TaskInfo>>(null);
}
_lastResponseHadTasksRunning = false;
}
return Task.FromResult(tasks
.OrderBy(i => i.Name)
.Select(ScheduledTaskHelpers.GetTaskInfo)
.Where(i => !i.IsHidden));

View File

@ -1,5 +1,4 @@
using System;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@ -8,6 +7,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Search;
using ServiceStack;
using System;
using System.Linq;
using System.Threading.Tasks;
@ -16,8 +16,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetSearchHints
/// </summary>
[Route("/Search/Hints", "GET")]
[Api(Description = "Gets search hints based on a search term")]
[Route("/Search/Hints", "GET", Summary = "Gets search hints based on a search term")]
public class GetSearchHints : IReturn<SearchHintResult>
{
/// <summary>

View File

@ -14,8 +14,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetSessions
/// </summary>
[Route("/Sessions", "GET")]
[Api(("Gets a list of sessions"))]
[Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
public class GetSessions : IReturn<List<SessionInfoDto>>
{
/// <summary>
@ -28,15 +27,14 @@ namespace MediaBrowser.Api
[ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public Guid? ControllableByUserId { get; set; }
[ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
[ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string DeviceId { get; set; }
}
/// <summary>
/// Class BrowseTo
/// </summary>
[Route("/Sessions/{Id}/Viewing", "POST")]
[Api(("Instructs a session to browse to an item or view"))]
[Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")]
public class BrowseTo : IReturnVoid
{
/// <summary>
@ -77,8 +75,7 @@ namespace MediaBrowser.Api
public string Context { get; set; }
}
[Route("/Sessions/{Id}/Playing", "POST")]
[Api(("Instructs a session to play an item"))]
[Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
public class Play : IReturnVoid
{
/// <summary>
@ -110,8 +107,7 @@ namespace MediaBrowser.Api
public PlayCommand PlayCommand { get; set; }
}
[Route("/Sessions/{Id}/Playing/{Command}", "POST")]
[Api(("Issues a playstate command to a client"))]
[Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
public class SendPlaystateCommand : IReturnVoid
{
/// <summary>
@ -135,8 +131,7 @@ namespace MediaBrowser.Api
public PlaystateCommand Command { get; set; }
}
[Route("/Sessions/{Id}/System/{Command}", "POST")]
[Api(("Issues a system command to a client"))]
[Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")]
public class SendSystemCommand : IReturnVoid
{
/// <summary>
@ -154,8 +149,7 @@ namespace MediaBrowser.Api
public SystemCommand Command { get; set; }
}
[Route("/Sessions/{Id}/Message", "POST")]
[Api(("Issues a command to a client to display a message to the user"))]
[Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")]
public class SendMessageCommand : IReturnVoid
{
/// <summary>
@ -175,8 +169,7 @@ namespace MediaBrowser.Api
public long? TimeoutMs { get; set; }
}
[Route("/Sessions/{Id}/Users/{UserId}", "POST")]
[Api(("Adds an additional user to a session"))]
[Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")]
public class AddUserToSession : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -186,8 +179,7 @@ namespace MediaBrowser.Api
public Guid UserId { get; set; }
}
[Route("/Sessions/{Id}/Users/{UserId}", "DELETE")]
[Api(("Removes an additional user from a session"))]
[Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")]
public class RemoveUserFromSession : IReturnVoid
{
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@ -197,8 +189,7 @@ namespace MediaBrowser.Api
public Guid UserId { get; set; }
}
[Route("/Sessions/{Id}/Capabilities", "POST")]
[Api(("Updates capabilities for a device"))]
[Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")]
public class PostCapabilities : IReturnVoid
{
/// <summary>

View File

@ -8,8 +8,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetSystemInfo
/// </summary>
[Route("/System/Info", "GET")]
[Api(Description = "Gets information about the server")]
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
public class GetSystemInfo : IReturn<SystemInfo>
{
@ -18,14 +17,12 @@ namespace MediaBrowser.Api
/// <summary>
/// Class RestartApplication
/// </summary>
[Route("/System/Restart", "POST")]
[Api(("Restarts the application, if needed"))]
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
public class RestartApplication
{
}
[Route("/System/Shutdown", "POST")]
[Api(("Shuts down the application"))]
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
public class ShutdownApplication
{
}

View File

@ -17,8 +17,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetNextUpEpisodes
/// </summary>
[Route("/Shows/NextUp", "GET")]
[Api(("Gets a list of next up episodes"))]
[Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")]
public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields
{
/// <summary>
@ -53,8 +52,7 @@ namespace MediaBrowser.Api
public string SeriesId { get; set; }
}
[Route("/Shows/Upcoming", "GET")]
[Api(("Gets a list of upcoming episodes"))]
[Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasItemFields
{
/// <summary>
@ -86,14 +84,12 @@ namespace MediaBrowser.Api
public string Fields { get; set; }
}
[Route("/Shows/{Id}/Similar", "GET")]
[Api(Description = "Finds tv shows similar to a given one.")]
[Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")]
public class GetSimilarShows : BaseGetSimilarItemsFromItem
{
}
[Route("/Shows/{Id}/Episodes", "GET")]
[Api(Description = "Gets episodes for a tv season")]
[Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields
{
/// <summary>
@ -129,8 +125,7 @@ namespace MediaBrowser.Api
public string AdjacentTo { get; set; }
}
[Route("/Shows/{Id}/Seasons", "GET")]
[Api(Description = "Gets seasons for a tv series")]
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
public class GetSeasons : IReturn<ItemsResult>, IHasItemFields
{
/// <summary>

View File

@ -17,8 +17,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetUsers
/// </summary>
[Route("/Users", "GET")]
[Api(Description = "Gets a list of users")]
[Route("/Users", "GET", Summary = "Gets a list of users")]
public class GetUsers : IReturn<List<UserDto>>
{
[ApiMember(Name = "IsHidden", Description = "Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
@ -28,8 +27,7 @@ namespace MediaBrowser.Api
public bool? IsDisabled { get; set; }
}
[Route("/Users/Public", "GET")]
[Api(Description = "Gets a list of publicly visible users for display on a login screen.")]
[Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
public class GetPublicUsers : IReturn<List<UserDto>>
{
}
@ -37,8 +35,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class GetUser
/// </summary>
[Route("/Users/{Id}", "GET")]
[Api(Description = "Gets a user by Id")]
[Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")]
public class GetUser : IReturn<UserDto>
{
/// <summary>
@ -52,8 +49,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class DeleteUser
/// </summary>
[Route("/Users/{Id}", "DELETE")]
[Api(Description = "Deletes a user")]
[Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")]
public class DeleteUser : IReturnVoid
{
/// <summary>
@ -67,8 +63,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class AuthenticateUser
/// </summary>
[Route("/Users/{Id}/Authenticate", "POST")]
[Api(Description = "Authenticates a user")]
[Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")]
public class AuthenticateUser : IReturn<AuthenticationResult>
{
/// <summary>
@ -89,8 +84,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class AuthenticateUser
/// </summary>
[Route("/Users/AuthenticateByName", "POST")]
[Api(Description = "Authenticates a user")]
[Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")]
public class AuthenticateUserByName : IReturn<AuthenticationResult>
{
/// <summary>
@ -111,8 +105,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdateUserPassword
/// </summary>
[Route("/Users/{Id}/Password", "POST")]
[Api(Description = "Updates a user's password")]
[Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")]
public class UpdateUserPassword : IReturnVoid
{
/// <summary>
@ -143,8 +136,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class UpdateUser
/// </summary>
[Route("/Users/{Id}", "POST")]
[Api(Description = "Updates a user")]
[Route("/Users/{Id}", "POST", Summary = "Updates a user")]
public class UpdateUser : UserDto, IReturnVoid
{
}
@ -152,8 +144,7 @@ namespace MediaBrowser.Api
/// <summary>
/// Class CreateUser
/// </summary>
[Route("/Users", "POST")]
[Api(Description = "Creates a user")]
[Route("/Users", "POST", Summary = "Creates a user")]
public class CreateUser : UserDto, IReturn<UserDto>
{
}

View File

@ -1,11 +1,11 @@
using System.Globalization;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
namespace MediaBrowser.Common.Net
{
@ -16,6 +16,7 @@ namespace MediaBrowser.Common.Net
/// <typeparam name="TStateType">The type of the T state type.</typeparam>
public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable
where TStateType : class, new()
where TReturnDataType : class
{
/// <summary>
/// The _active connections
@ -144,12 +145,15 @@ namespace MediaBrowser.Common.Net
var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false);
if (data != null)
{
await connection.SendAsync(new WebSocketMessage<TReturnDataType>
{
MessageType = Name,
Data = data
}, tuple.Item2.Token).ConfigureAwait(false);
}
tuple.Item5.Release();
}

View File

@ -6,12 +6,12 @@ namespace MediaBrowser.Controller.Dlna
public class CodecProfile
{
public CodecType Type { get; set; }
public List<ProfileCondition> Conditions { get; set; }
public ProfileCondition[] Conditions { get; set; }
public string Codec { get; set; }
public CodecProfile()
{
Conditions = new List<ProfileCondition>();
Conditions = new ProfileCondition[] {};
}
public List<string> GetCodecs()
@ -32,6 +32,12 @@ namespace MediaBrowser.Controller.Dlna
public ProfileConditionType Condition { get; set; }
public ProfileConditionValue Property { get; set; }
public string Value { get; set; }
public bool IsRequired { get; set; }
public ProfileCondition()
{
IsRequired = true;
}
}
public enum ProfileConditionType
@ -46,11 +52,17 @@ namespace MediaBrowser.Controller.Dlna
{
AudioChannels,
AudioBitrate,
AudioProfile,
Filesize,
Width,
Height,
Has64BitOffsets,
VideoBitDepth,
VideoBitrate,
VideoFramerate,
VideoLevel
VideoLevel,
VideoPacketLength,
VideoProfile,
VideoTimestamp
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Dlna
{
public class ContainerProfile
{
public DlnaProfileType Type { get; set; }
public ProfileCondition[] Conditions { get; set; }
public string Container { get; set; }
public ContainerProfile()
{
Conditions = new ProfileCondition[] { };
}
public List<string> GetContainers()
{
return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
}
}
}

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;

namespace MediaBrowser.Controller.Dlna
{
public class DeviceIdentification
@ -55,11 +54,11 @@ namespace MediaBrowser.Controller.Dlna
/// Gets or sets the headers.
/// </summary>
/// <value>The headers.</value>
public List<HttpHeaderInfo> Headers { get; set; }
public HttpHeaderInfo[] Headers { get; set; }
public DeviceIdentification()
{
Headers = new List<HttpHeaderInfo>();
Headers = new HttpHeaderInfo[] {};
}
}
@ -73,6 +72,7 @@ namespace MediaBrowser.Controller.Dlna
public enum HeaderMatchType
{
Equals = 0,
Substring = 1
Regex = 1,
Substring = 2
}
}

View File

@ -27,6 +27,8 @@ namespace MediaBrowser.Controller.Dlna
/// <value>The direct play profiles.</value>
public DirectPlayProfile[] DirectPlayProfiles { get; set; }
public ContainerProfile[] ContainerProfiles { get; set; }
/// <summary>
/// Gets or sets the identification.
/// </summary>
@ -40,6 +42,9 @@ namespace MediaBrowser.Controller.Dlna
public string ModelDescription { get; set; }
public string ModelNumber { get; set; }
public string ModelUrl { get; set; }
public bool IgnoreTranscodeByteRangeRequests { get; set; }
public bool SupportsAlbumArtInDidl { get; set; }
/// <summary>
/// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.
/// </summary>
@ -60,12 +65,16 @@ namespace MediaBrowser.Controller.Dlna
public int TimelineOffsetSeconds { get; set; }
public bool RequiresPlainVideoItems { get; set; }
public bool RequiresPlainFolders { get; set; }
public DeviceProfile()
{
DirectPlayProfiles = new DirectPlayProfile[] { };
TranscodingProfiles = new TranscodingProfile[] { };
MediaProfiles = new MediaProfile[] { };
CodecProfiles = new CodecProfile[] { };
ContainerProfiles = new ContainerProfile[] { };
}
}
}

View File

@ -5,19 +5,15 @@ namespace MediaBrowser.Controller.Dlna
{
public class DirectPlayProfile
{
public string[] Containers { get; set; }
public string Container { get; set; }
public string AudioCodec { get; set; }
public string VideoCodec { get; set; }
public DlnaProfileType Type { get; set; }
public List<ProfileCondition> Conditions { get; set; }
public DirectPlayProfile()
public List<string> GetContainers()
{
Conditions = new List<ProfileCondition>();
Containers = new string[] { };
return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
}
public List<string> GetAudioCodecs()

View File

@ -13,6 +13,13 @@ namespace MediaBrowser.Controller.Dlna
public string OrgPn { get; set; }
public string MimeType { get; set; }
public ProfileCondition[] Conditions { get; set; }
public MediaProfile()
{
Conditions = new ProfileCondition[] {};
}
public List<string> GetAudioCodecs()
{
return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();

View File

@ -1,5 +1,4 @@
using System.Collections.Generic;

namespace MediaBrowser.Controller.Dlna
{
public class TranscodingProfile
@ -11,12 +10,18 @@ namespace MediaBrowser.Controller.Dlna
public string VideoCodec { get; set; }
public string AudioCodec { get; set; }
public List<TranscodingSetting> Settings { get; set; }
public bool EstimateContentLength { get; set; }
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
public TranscodingSetting[] Settings { get; set; }
public TranscodingProfile()
{
Settings = new List<TranscodingSetting>();
Settings = new TranscodingSetting[] { };
}
public bool EnableMpegtsM2TsMode { get; set; }
}
public class TranscodingSetting
@ -27,6 +32,14 @@ namespace MediaBrowser.Controller.Dlna
public enum TranscodingSettingType
{
Profile
VideoLevel = 0,
VideoProfile = 1,
MaxAudioChannels = 2
}
public enum TranscodeSeekInfo
{
Auto = 0,
Bytes = 1
}
}

View File

@ -79,6 +79,7 @@
<Compile Include="Collections\CollectionCreationOptions.cs" />
<Compile Include="Collections\ICollectionManager.cs" />
<Compile Include="Dlna\CodecProfile.cs" />
<Compile Include="Dlna\ContainerProfile.cs" />
<Compile Include="Dlna\DeviceIdentification.cs" />
<Compile Include="Dlna\DirectPlayProfile.cs" />
<Compile Include="Dlna\IDlnaManager.cs" />

View File

@ -1,6 +1,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Dlna.Profiles;
using MediaBrowser.Model.Serialization;
using System.Collections.Generic;
using System.Linq;
@ -13,849 +14,42 @@ namespace MediaBrowser.Dlna
private IApplicationPaths _appPaths;
private readonly IXmlSerializer _xmlSerializer;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem)
public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
{
_xmlSerializer = xmlSerializer;
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
//GetProfiles();
GetProfiles();
}
public IEnumerable<DeviceProfile> GetProfiles()
{
var list = new List<DeviceProfile>();
list.Add(new DeviceProfile
{
Name = "Samsung TV (B Series)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = "^TV$",
ModelNumber = @"1\.0",
ModelName = "Samsung DTV DMR"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio,
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio,
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Samsung TV (E/F-series)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"(^\[TV\][A-Z]{2}\d{2}(E|F)[A-Z]?\d{3,4}.*)|^\[TV\] Samsung|(^\[TV\]Samsung [A-Z]{2}\d{2}(E|F)[A-Z]?\d{3,4}.*)",
ModelNumber = @"(1\.0)|(AllShare1\.0)"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Samsung TV (C/D-series)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"(^TV-\d{2}C\d{3}.*)|(^\[TV\][A-Z]{2}\d{2}(D)[A-Z]?\d{3,4}.*)|^\[TV\] Samsung",
ModelNumber = @"(1\.0)|(AllShare1\.0)"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Xbox 360",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
ModelName = "Xbox 360"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Xbox One",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
ModelName = "Xbox One",
FriendlyName = "Xbox-SystemOS"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Sony Bravia (2012)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"BRAVIA KDL-\d{2}[A-Z]X\d5(\d|G).*"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"asf"},
Type = DlnaProfileType.Audio
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="asf",
MimeType = "video/x-ms-wmv",
Type = DlnaProfileType.Audio
}
}
});
list.Add(new DeviceProfile
{
Name = "Sony Bravia (2013)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"BRAVIA (KDL-\d{2}W[689]\d{2}A.*)|(KD-\d{2}X9\d{3}A.*)"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"wma"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="mp4",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="ts",
MimeType = "video/mpeg",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="wma",
MimeType = "video/x-ms-wma",
Type = DlnaProfileType.Audio
}
}
});
list.Add(new DeviceProfile
{
//Panasonic Viera (2011|2012) Without AVI Support
Name = "Panasonic Viera E/S/ST/VT (2011)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"(VIERA (E|S)T?(3|5)0?.*)|(VIERA VT30.*)",
Manufacturer = "Panasonic"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
//Panasonic Viera (2011|2012) With AVI Support
Name = "Panasonic Viera G/GT/DT/UT/VT (2011/2012)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"(VIERA (G|D|U)T?(3|5)0?.*)|(VIERA VT50.*)",
Manufacturer = "Panasonic"
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/divx",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Philips (2010-)",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = ".*PHILIPS.*",
ModelName = "WD TV HD Live"
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3", "wma"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container ="mkv",
MimeType = "video/x-matroska",
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "WDTV Live",
ClientType = "DLNA",
TimelineOffsetSeconds = 5,
Identification = new DeviceIdentification
{
ModelName = "WD TV HD Live",
Headers = new List<HttpHeaderInfo>
{
new HttpHeaderInfo{ Name="User-Agent", Value="alphanetworks", Match= HeaderMatchType.Substring},
new HttpHeaderInfo{ Name="User-Agent", Value="ALPHA Networks", Match= HeaderMatchType.Substring}
}
},
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio,
AudioCodec = "mp3"
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
VideoCodec = "h264",
AudioCodec = "aac"
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"avi"},
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Containers = new[]{"mpeg"},
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,dca,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Containers = new[]{"mkv"},
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,aac,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Containers = new[]{"ts"},
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3"
},
new DirectPlayProfile
{
Containers = new[]{"mp4", "mov"},
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp2,mp3"
},
new DirectPlayProfile
{
Containers = new[]{"asf"},
Type = DlnaProfileType.Video,
VideoCodec = "vc1",
AudioCodec = "wmav2,wmapro"
},
new DirectPlayProfile
{
Containers = new[]{"asf"},
Type = DlnaProfileType.Video,
VideoCodec = "mpeg2video",
AudioCodec = "mp2,ac3"
},
new DirectPlayProfile
{
Containers = new[]{"mp3"},
AudioCodec = "mp2,mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"mp4"},
AudioCodec = "mp4",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"flac"},
AudioCodec = "flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"asf"},
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"ogg"},
AudioCodec = "vorbis",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Type = DlnaProfileType.Photo,
Containers = new[]{"jpeg", "png", "gif", "bmp", "tiff"},
Conditions = new List<ProfileCondition>
{
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Width, Value = "1920"},
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Height, Value = "1080"}
}
}
},
MediaProfiles = new[]
{
new MediaProfile
{
Container ="ts",
OrgPn = "MPEG_TS_SD_NA",
Type = DlnaProfileType.Video
}
},
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec= "h264",
Conditions = new List<ProfileCondition>
{
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Width, Value = "1920"},
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Height, Value = "1080"},
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.VideoLevel, Value = "41"}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec= "aac",
Conditions = new List<ProfileCondition>
{
new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, Value = "2"}
}
}
}
});
list.Add(new DeviceProfile
{
// Linksys DMA2100us does not need any transcoding of the formats we support statically
Name = "Linksys DMA2100",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
ModelName = "DMA2100us"
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3", "flac", "m4a", "wma"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi", "mp4", "mkv", "ts"},
Type = DlnaProfileType.Video
}
}
});
list.Add(new DeviceProfile
{
Name = "Denon AVR",
ClientType = "DLNA",
Identification = new DeviceIdentification
{
FriendlyName = @"Denon:\[AVR:.*",
Manufacturer = "Denon"
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3", "flac", "m4a", "wma"},
Type = DlnaProfileType.Audio
},
}
});
var list = new List<DeviceProfile>
{
new SamsungSmartTvProfile(),
new Xbox360Profile(),
new XboxOneProfile(),
new SonyPs3Profile(),
new SonyBravia2010Profile(),
new SonyBravia2011Profile(),
new SonyBravia2012Profile(),
new SonyBravia2013Profile(),
new SonyBlurayPlayer2013Profile(),
new SonyBlurayPlayerProfile(),
new PanasonicVieraProfile(),
new WdtvLiveProfile(),
new DenonAvrProfile(),
new LinksysDMA2100Profile(),
new LgTvProfile()
};
foreach (var item in list)
{
//_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name));
//_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml");
//_jsonSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".json");
}
return list;
@ -863,37 +57,7 @@ namespace MediaBrowser.Dlna
public DeviceProfile GetDefaultProfile()
{
return new DeviceProfile
{
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video
}
},
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Containers = new[]{"mp3", "wma"},
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Containers = new[]{"avi", "mp4"},
Type = DlnaProfileType.Video
}
}
};
return new DefaultProfile();
}
public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
@ -906,55 +70,55 @@ namespace MediaBrowser.Dlna
{
if (!string.IsNullOrWhiteSpace(profileInfo.DeviceDescription))
{
if (!Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
if (deviceInfo.DeviceDescription == null || !Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.FriendlyName))
{
if (!Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
if (deviceInfo.FriendlyName == null || !Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.Manufacturer))
{
if (!Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
if (deviceInfo.Manufacturer == null || !Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.ManufacturerUrl))
{
if (!Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
if (deviceInfo.ManufacturerUrl == null || !Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.ModelDescription))
{
if (!Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
if (deviceInfo.ModelDescription == null || !Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.ModelName))
{
if (!Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName))
if (deviceInfo.ModelName == null || !Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.ModelNumber))
{
if (!Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
if (deviceInfo.ModelNumber == null || !Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.ModelUrl))
{
if (!Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
if (deviceInfo.ModelUrl == null || !Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
return false;
}
if (!string.IsNullOrWhiteSpace(profileInfo.SerialNumber))
{
if (!Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
if (deviceInfo.SerialNumber == null || !Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
return false;
}

View File

@ -81,7 +81,28 @@
<Compile Include="PlayTo\uIcon.cs" />
<Compile Include="PlayTo\uParser.cs" />
<Compile Include="PlayTo\uPnpNamespaces.cs" />
<Compile Include="Profiles\DefaultProfile.cs" />
<Compile Include="Profiles\DenonAvrProfile.cs" />
<Compile Include="Profiles\LgTvProfile.cs" />
<Compile Include="Profiles\LinksysDMA2100Profile.cs" />
<Compile Include="Profiles\PanasonicVieraProfile.cs" />
<Compile Include="Profiles\SamsungSmartTvProfile.cs" />
<Compile Include="Profiles\SonyBlurayPlayer2013Profile.cs" />
<Compile Include="Profiles\SonyBlurayPlayerProfile.cs" />
<Compile Include="Profiles\SonyBravia2010Profile.cs" />
<Compile Include="Profiles\SonyBravia2011Profile.cs" />
<Compile Include="Profiles\SonyBravia2012Profile.cs" />
<Compile Include="Profiles\SonyBravia2013Profile.cs" />
<Compile Include="Profiles\SonyPs3Profile.cs" />
<Compile Include="Profiles\WdtvLiveProfile.cs" />
<Compile Include="Profiles\Xbox360Profile.cs" />
<Compile Include="Profiles\XboxOneProfile.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server\DlnaServerEntryPoint.cs" />
<Compile Include="Server\Headers.cs" />
<Compile Include="Server\RawHeaders.cs" />
<Compile Include="Server\SsdpHandler.cs" />
<Compile Include="Server\UpnpDevice.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
@ -97,9 +118,7 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Server\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -681,6 +681,9 @@ namespace MediaBrowser.Dlna.PlayTo
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
if (presentationUrl != null)
deviceProperties.PresentationUrl = presentationUrl.Value;
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
if (modelUrl != null)
deviceProperties.ModelUrl = modelUrl.Value;
deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);

View File

@ -34,6 +34,8 @@ namespace MediaBrowser.Dlna.PlayTo
public string ModelNumber { get; set; }
public string ModelUrl { get; set; }
public string Manufacturer { get; set; }
public string ManufacturerUrl { get; set; }
@ -72,7 +74,8 @@ namespace MediaBrowser.Dlna.PlayTo
ModelName = ModelName,
ModelNumber = ModelNumber,
FriendlyName = Name,
ManufacturerUrl = ManufacturerUrl
ManufacturerUrl = ManufacturerUrl,
ModelUrl = ModelUrl
};
}
}

View File

@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.StartPositionTicks = newItem.StartPositionTicks;
playlistItem.StreamUrl = newItem.StreamUrl;
playlistItem.Didl = newItem.Didl;
return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl);
return _device.SetAvTransport(playlistItem.StreamUrl, GetDlnaHeaders(playlistItem), playlistItem.Didl);
}
return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0));
@ -391,16 +391,23 @@ namespace MediaBrowser.Dlna.PlayTo
private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
{
var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList();
var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery
{
ItemId = item.Id
}).ToList();
var deviceInfo = _device.Properties;
var playlistItem = GetPlaylistItem(item, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()));
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification());
var playlistItem = GetPlaylistItem(item, streams, profile);
playlistItem.StartPositionTicks = startPostionTicks;
playlistItem.DeviceProfileName = profile.Name;
if (playlistItem.MediaType == DlnaProfileType.Audio)
{
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(deviceInfo, playlistItem, streams, serverAddress);
}
else
{
@ -410,32 +417,92 @@ namespace MediaBrowser.Dlna.PlayTo
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
playlistItem.Didl = didl;
var header = StreamHelper.GetDlnaHeaders(playlistItem);
playlistItem.DlnaHeaders = header;
return playlistItem;
}
private PlaylistItem GetPlaylistItem(BaseItem item, DeviceProfile profile)
private string GetDlnaHeaders(PlaylistItem item)
{
var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
string contentFeatures;
var container = item.Container.TrimStart('.');
if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MP3";
}
else if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMABASE";
}
else if (string.Equals(container, "wmw", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
}
else if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
}
else if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=AVI";
}
else if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MATROSKA";
}
else if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
}
else if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
}
else if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
}
else if (item.MediaType == DlnaProfileType.Video)
{
// Default to AVI for video
contentFeatures = "DLNA.ORG_PN=AVI";
}
else
{
// Default to MP3 for audio
contentFeatures = "DLNA.ORG_PN=MP3";
}
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
}
private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaStream> mediaStreams, DeviceProfile profile)
{
var video = item as Video;
if (video != null)
{
return new PlaylistItemFactory(_itemRepository).Create(video, profile);
return new PlaylistItemFactory().Create(video, mediaStreams, profile);
}
var audio = item as Audio;
if (audio != null)
{
return new PlaylistItemFactory(_itemRepository).Create(audio, profile);
return new PlaylistItemFactory().Create(audio, mediaStreams, profile);
}
var photo = item as Photo;
if (photo != null)
{
return new PlaylistItemFactory(_itemRepository).Create(photo, profile);
return new PlaylistItemFactory().Create(photo, profile);
}
throw new ArgumentException("Unrecognized item type.");
@ -482,11 +549,18 @@ namespace MediaBrowser.Dlna.PlayTo
await _device.SetStop();
return true;
}
nextTrack.PlayState = 1;
_logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, nextTrack.DlnaHeaders);
await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl);
var dlnaheaders = GetDlnaHeaders(nextTrack);
_logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, dlnaheaders);
await _device.SetAvTransport(nextTrack.StreamUrl, dlnaheaders, nextTrack.Didl);
if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
return true;
}
@ -508,7 +582,7 @@ namespace MediaBrowser.Dlna.PlayTo
return Task.FromResult(false);
prevTrack.PlayState = 1;
return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl);
return _device.SetAvTransport(prevTrack.StreamUrl, GetDlnaHeaders(prevTrack), prevTrack.Didl);
}
#endregion

View File

@ -7,6 +7,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Session;
using System;
using System.Collections.Concurrent;
using System.Linq;
@ -16,7 +17,6 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Session;
namespace MediaBrowser.Dlna.PlayTo
{
@ -54,10 +54,8 @@ namespace MediaBrowser.Dlna.PlayTo
_config = config;
}
public async void Start()
public void Start()
{
_logger.Log(LogSeverity.Info, "PlayTo-Manager starting");
_locations = new ConcurrentDictionary<string, DateTime>();
foreach (var network in NetworkInterface.GetAllNetworkInterfaces())
@ -73,7 +71,7 @@ namespace MediaBrowser.Dlna.PlayTo
IPAddress localIp = null;
foreach (UnicastIPAddressInformation ipInfo in network.GetIPProperties().UnicastAddresses)
foreach (var ipInfo in network.GetIPProperties().UnicastAddresses)
{
if (ipInfo.Address.AddressFamily == AddressFamily.InterNetwork)
{
@ -95,8 +93,6 @@ namespace MediaBrowser.Dlna.PlayTo
{
_logger.ErrorException("Failed to Initilize Socket", e);
}
await Task.Delay(100).ConfigureAwait(false);
}
}
@ -139,7 +135,7 @@ namespace MediaBrowser.Dlna.PlayTo
_logger.Info("SSDP listener - Task completed");
}
catch (OperationCanceledException c)
catch (OperationCanceledException)
{
}
catch (Exception e)
@ -158,7 +154,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
await CreateController(uri).ConfigureAwait(false);
}
catch (OperationCanceledException c)
catch (OperationCanceledException)
{
}
catch (Exception ex)
@ -180,10 +176,12 @@ namespace MediaBrowser.Dlna.PlayTo
{
socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900));
await Task.Delay(10000).ConfigureAwait(false);
var delay = _config.Configuration.DlnaOptions.ClientDiscoveryIntervalSeconds * 1000;
await Task.Delay(delay).ConfigureAwait(false);
}
}
catch (OperationCanceledException c)
catch (OperationCanceledException)
{
}
catch (Exception ex)

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Dlna;
using System.Collections.Generic;
namespace MediaBrowser.Dlna.PlayTo
{
@ -14,16 +15,29 @@ namespace MediaBrowser.Dlna.PlayTo
public string Container { get; set; }
public string MimeType { get; set; }
public int PlayState { get; set; }
public string StreamUrl { get; set; }
public string DlnaHeaders { get; set; }
public string Didl { get; set; }
public long StartPositionTicks { get; set; }
public string VideoCodec { get; set; }
public string AudioCodec { get; set; }
public List<TranscodingSetting> TranscodingSettings { get; set; }
public int? AudioStreamIndex { get; set; }
public int? SubtitleStreamIndex { get; set; }
public string DeviceProfileName { get; set; }
public PlaylistItem()
{
TranscodingSettings = new List<TranscodingSetting>();
}
}
}

View File

@ -1,9 +1,9 @@
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -12,15 +12,9 @@ namespace MediaBrowser.Dlna.PlayTo
{
public class PlaylistItemFactory
{
private readonly IItemRepository _itemRepo;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
public PlaylistItemFactory(IItemRepository itemRepo)
{
_itemRepo = itemRepo;
}
public PlaylistItem Create(Audio item, DeviceProfile profile)
public PlaylistItem Create(Audio item, List<MediaStream> mediaStreams, DeviceProfile profile)
{
var playlistItem = new PlaylistItem
{
@ -28,14 +22,11 @@ namespace MediaBrowser.Dlna.PlayTo
MediaType = DlnaProfileType.Audio
};
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
{
ItemId = item.Id,
Type = MediaStreamType.Audio
});
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec)
.All(i => IsCodecProfileSupported(i, item.Path, null, audioStream)))
{
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
@ -46,6 +37,7 @@ namespace MediaBrowser.Dlna.PlayTo
return playlistItem;
}
}
var transcodingProfile = profile.TranscodingProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
@ -53,12 +45,11 @@ namespace MediaBrowser.Dlna.PlayTo
if (transcodingProfile != null)
{
playlistItem.Transcode = true;
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec;
}
AttachMediaProfile(playlistItem, profile);
return playlistItem;
}
@ -87,16 +78,14 @@ namespace MediaBrowser.Dlna.PlayTo
if (transcodingProfile != null)
{
playlistItem.Transcode = true;
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
}
AttachMediaProfile(playlistItem, profile);
return playlistItem;
}
public PlaylistItem Create(Video item, DeviceProfile profile)
public PlaylistItem Create(Video item, List<MediaStream> mediaStreams, DeviceProfile profile)
{
var playlistItem = new PlaylistItem
{
@ -104,15 +93,12 @@ namespace MediaBrowser.Dlna.PlayTo
MediaType = DlnaProfileType.Video
};
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
{
ItemId = item.Id
}).ToList();
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec || i.Type == CodecType.VideoAudioCodec)
.All(i => IsCodecProfileSupported(i, item.Path, videoStream, audioStream)))
{
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
@ -123,6 +109,7 @@ namespace MediaBrowser.Dlna.PlayTo
return playlistItem;
}
}
var transcodingProfile = profile.TranscodingProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
@ -130,63 +117,29 @@ namespace MediaBrowser.Dlna.PlayTo
if (transcodingProfile != null)
{
playlistItem.Transcode = true;
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault();
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
}
AttachMediaProfile(playlistItem, profile);
return playlistItem;
}
private void AttachMediaProfile(PlaylistItem item, DeviceProfile profile)
{
var mediaProfile = GetMediaProfile(item, profile);
if (mediaProfile != null)
{
item.MimeType = (mediaProfile.MimeType ?? string.Empty).Split('/').LastOrDefault();
// TODO: Org_pn?
}
}
private MediaProfile GetMediaProfile(PlaylistItem item, DeviceProfile profile)
{
return profile.MediaProfiles.FirstOrDefault(i =>
{
if (i.Type == item.MediaType)
{
if (string.Equals(item.Container.TrimStart('.'), i.Container.TrimStart('.'), StringComparison.OrdinalIgnoreCase))
{
// TODO: Enforce codecs
return true;
}
}
return false;
});
}
private bool IsSupported(DirectPlayProfile profile, Photo item)
{
var mediaPath = item.Path;
if (profile.Containers.Length > 0)
if (profile.Container.Length > 0)
{
// Check container type
var mediaContainer = Path.GetExtension(mediaPath);
if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, null)))
{
return false;
}
return true;
}
@ -194,22 +147,16 @@ namespace MediaBrowser.Dlna.PlayTo
{
var mediaPath = item.Path;
if (profile.Containers.Length > 0)
if (profile.Container.Length > 0)
{
// Check container type
var mediaContainer = Path.GetExtension(mediaPath);
if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, audioStream)))
{
return false;
}
return true;
}
@ -222,11 +169,11 @@ namespace MediaBrowser.Dlna.PlayTo
var mediaPath = item.Path;
if (profile.Containers.Length > 0)
if (profile.Container.Length > 0)
{
// Check container type
var mediaContainer = Path.GetExtension(mediaPath);
if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
@ -254,12 +201,6 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream)))
{
return false;
}
return true;
}
@ -281,6 +222,24 @@ namespace MediaBrowser.Dlna.PlayTo
return true;
}
private bool IsCodecProfileSupported(CodecProfile profile, string mediaPath, MediaStream videoStream, MediaStream audioStream)
{
var codecs = profile.GetCodecs();
var stream = profile.Type == CodecType.VideoCodec ? videoStream : audioStream;
var existingCodec = (stream == null ? null : stream.Codec) ?? string.Empty;
if (codecs.Count == 0 || codecs.Contains(existingCodec, StringComparer.OrdinalIgnoreCase))
{
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream)))
{
return false;
}
}
return true;
}
/// <summary>
/// Determines whether [is condition satisfied] [the specified condition].
/// </summary>
@ -291,6 +250,49 @@ namespace MediaBrowser.Dlna.PlayTo
/// <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);
@ -314,8 +316,10 @@ namespace MediaBrowser.Dlna.PlayTo
}
}
}
}
return false;
// Value doesn't exist in metadata. Fail it if required.
return !condition.IsRequired;
}
/// <summary>
@ -347,6 +351,12 @@ namespace MediaBrowser.Dlna.PlayTo
return videoStream == null ? null : videoStream.Width;
case ProfileConditionValue.VideoLevel:
return videoStream == null ? null : ConvertToLong(videoStream.Level);
case ProfileConditionValue.VideoPacketLength:
// TODO: Determine how to get this
return null;
case ProfileConditionValue.VideoTimestamp:
// TODO: Determine how to get this
return null;
default:
throw new InvalidOperationException("Unexpected Property");
}

View File

@ -49,7 +49,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
Url = url.ToString(),
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
options.RequestHeaders["HOST"] = ip + ":" + port;
@ -88,7 +88,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
Url = url.ToString(),
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
@ -112,7 +112,7 @@ namespace MediaBrowser.Dlna.PlayTo
{
Url = url.ToString(),
UserAgent = USERAGENT,
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
};
options.RequestHeaders["SOAPAction"] = soapAction;

View File

@ -1,6 +1,5 @@
using MediaBrowser.Model.Dto;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -9,91 +8,21 @@ namespace MediaBrowser.Dlna.PlayTo
{
class StreamHelper
{
/// <summary>
/// Gets the dlna headers.
/// </summary>
/// <param name="item">The item.</param>
/// <returns></returns>
internal static string GetDlnaHeaders(PlaylistItem item)
{
var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
var contentFeatures = string.Empty;
if (string.Equals(item.Container, "mp3", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MP3";
}
else if (string.Equals(item.Container, "wma", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMABASE";
}
else if (string.Equals(item.Container, "wmw", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
}
else if (string.Equals(item.Container, "asf", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
}
else if (string.Equals(item.Container, "avi", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=AVI";
}
else if (string.Equals(item.Container, "mkv", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MATROSKA";
}
else if (string.Equals(item.Container, "mp4", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
}
else if (string.Equals(item.Container, "mpeg", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
}
else if (string.Equals(item.Container, "ts", StringComparison.OrdinalIgnoreCase))
{
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
}
else if (item.MediaType == Controller.Dlna.DlnaProfileType.Video)
{
//Default to AVI for video
contentFeatures = "DLNA.ORG_PN=AVI";
}
else
{
//Default to MP3 for audio
contentFeatures = "DLNA.ORG_PN=MP3";
}
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
}
#region Audio
/// <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(PlaylistItem item, string serverAddress)
internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{
if (!item.Transcode)
return string.Format("{0}/audio/{1}/stream{2}?Static=True", serverAddress, item.ItemId, item.Container);
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, null, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, null, 128000, item.StartPositionTicks, item.TranscodingSettings);
return string.Format("{0}/audio/{1}/stream.mp3?AudioCodec=Mp3", serverAddress, item.ItemId);
return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand);
}
#endregion
#region Video
/// <summary>
/// Gets the video URL.
/// </summary>
@ -104,97 +33,41 @@ namespace MediaBrowser.Dlna.PlayTo
/// <returns>The url to send to the device</returns>
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{
string dlnaCommand = string.Empty;
if (!item.Transcode)
{
dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, null, null, null, null, null, null, null, null, null, null, item.MimeType);
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, item.VideoCodec, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, 1500000, 128000, item.StartPositionTicks, item.TranscodingSettings);
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
}
var videostream = streams.Where(m => m.Type == MediaStreamType.Video).OrderBy(m => m.IsDefault).FirstOrDefault();
var audiostream = streams.Where(m => m.Type == MediaStreamType.Audio).OrderBy(m => m.IsDefault).FirstOrDefault();
var videoCodec = GetVideoCodec(videostream);
var audioCodec = GetAudioCodec(audiostream);
int? videoBitrate = null;
int? audioBitrate = null;
int? audioChannels = null;
if (videoCodec != VideoCodecs.Copy)
videoBitrate = 2000000;
if (audioCodec != AudioCodecs.Copy)
{
audioBitrate = 128000;
audioChannels = 2;
}
dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, videoCodec, audioCodec, null, null, videoBitrate, audioChannels, audioBitrate, item.StartPositionTicks, "baseline", "3", item.MimeType);
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
}
/// <summary>
/// Gets the video codec.
/// </summary>
/// <param name="videoStream">The video stream.</param>
/// <returns></returns>
private static VideoCodecs GetVideoCodec(MediaStream videoStream)
{
switch (videoStream.Codec.ToLower())
{
case "h264":
case "mpeg4":
return VideoCodecs.Copy;
}
return VideoCodecs.H264;
}
/// <summary>
/// Gets the audio codec.
/// </summary>
/// <param name="audioStream">The audio stream.</param>
/// <returns></returns>
private static AudioCodecs GetAudioCodec(MediaStream audioStream)
{
if (audioStream != null)
{
switch (audioStream.Codec.ToLower())
{
case "aac":
case "mp3":
case "wma":
return AudioCodecs.Copy;
}
}
return AudioCodecs.Aac;
}
/// <summary>
/// Builds the dlna URL.
/// </summary>
private static string BuildDlnaUrl(string deviceID, bool isStatic, VideoCodecs? videoCodec, AudioCodecs? audioCodec, int? subtitleIndex, int? audiostreamIndex, int? videoBitrate, int? audiochannels, int? audioBitrate, long? startPositionTicks, string profile, string videoLevel, string mimeType)
private static string BuildDlnaUrl(string deviceProfileName, string mediaSourceId, string deviceID, bool isStatic, string videoCodec, string audioCodec, int? audiostreamIndex, int? subtitleIndex, int? videoBitrate, int? audioBitrate, long? startPositionTicks, List<TranscodingSetting> settings)
{
var profile = settings.Where(i => i.Name == TranscodingSettingType.VideoProfile).Select(i => i.Value).FirstOrDefault();
var videoLevel = settings.Where(i => i.Name == TranscodingSettingType.VideoLevel).Select(i => i.Value).FirstOrDefault();
var maxAudioChannels = settings.Where(i => i.Name == TranscodingSettingType.MaxAudioChannels).Select(i => i.Value).FirstOrDefault();
var usCulture = new CultureInfo("en-US");
var dlnaparam = string.Format("Params={0};", deviceID);
dlnaparam += isStatic ? "true;" : "false;";
dlnaparam += videoCodec.HasValue ? videoCodec.Value + ";" : ";";
dlnaparam += audioCodec.HasValue ? audioCodec.Value + ";" : ";";
dlnaparam += audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) + ";" : ";";
dlnaparam += subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) + ";" : ";";
dlnaparam += videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) + ";" : ";";
dlnaparam += audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) + ";" : ";";
dlnaparam += audiochannels.HasValue ? audiochannels.Value.ToString(usCulture) + ";" : ";";
dlnaparam += startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) + ";" : ";";
dlnaparam += profile + ";";
dlnaparam += videoLevel + ";";
dlnaparam += mimeType + ";";
return dlnaparam;
}
#endregion
var list = new List<string>
{
deviceProfileName ?? string.Empty,
deviceID ?? string.Empty,
mediaSourceId ?? string.Empty,
isStatic.ToString().ToLower(),
videoCodec ?? string.Empty,
audioCodec ?? string.Empty,
audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty,
subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty,
videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty,
audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty,
maxAudioChannels ?? string.Empty,
startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty,
profile ?? string.Empty,
videoLevel ?? string.Empty
};
return string.Format("Params={0}", string.Join(";", list.ToArray()));
}
}
}

View File

@ -0,0 +1,59 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class DefaultProfile : DeviceProfile
{
public DefaultProfile()
{
ProtocolInfo = "DLNA";
ClientType = "DLNA";
Manufacturer = "Media Browser";
ModelDescription = "Media Browser";
ModelName = "Media Browser";
ModelNumber = "Media Browser";
ModelUrl = "http://mediabrowser3.com/";
ManufacturerUrl = "http://mediabrowser3.com/";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
AudioCodec = "aac",
VideoCodec = "h264",
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,wma",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "avi,mp4",
Type = DlnaProfileType.Video
}
};
}
}
}

View File

@ -0,0 +1,27 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class DenonAvrProfile : DefaultProfile
{
public DenonAvrProfile()
{
Name = "Denon AVR";
Identification = new DeviceIdentification
{
FriendlyName = @"Denon:\[AVR:.*",
Manufacturer = "Denon"
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,flac,m4a,wma",
Type = DlnaProfileType.Audio
},
};
}
}
}

View File

@ -0,0 +1,192 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class LgTvProfile : DefaultProfile
{
public LgTvProfile()
{
Name = "LG Smart TV";
TimelineOffsetSeconds = 10;
Identification = new DeviceIdentification
{
FriendlyName = @"LG.*",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "LG",
Match = HeaderMatchType.Substring
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3",
VideoCodec = "h264",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg4",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3,aac,mp3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
}
};
}
}
}

View File

@ -0,0 +1,33 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class LinksysDMA2100Profile : DefaultProfile
{
public LinksysDMA2100Profile()
{
// Linksys DMA2100us does not need any transcoding of the formats we support statically
Name = "Linksys DMA2100";
Identification = new DeviceIdentification
{
ModelName = "DMA2100us"
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,flac,m4a,wma",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "avi,mp4,mkv,ts",
Type = DlnaProfileType.Video
}
};
}
}
}

View File

@ -0,0 +1,186 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class PanasonicVieraProfile : DefaultProfile
{
public PanasonicVieraProfile()
{
Name = "Panasonic Viera";
Identification = new DeviceIdentification
{
FriendlyName = @"VIERA",
Manufacturer = "Panasonic",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "Panasonic MIL DLNA",
Match = HeaderMatchType.Substring
}
}
};
TimelineOffsetSeconds = 10;
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3",
VideoCodec = "h264",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg4",
AudioCodec = "ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mov",
VideoCodec = "h264",
AudioCodec = "aac,pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "flv",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "aac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth,
Value = "8",
IsRequired = false
}
}
}
};
}
}
}

View File

@ -0,0 +1,315 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SamsungSmartTvProfile : DefaultProfile
{
public SamsungSmartTvProfile()
{
Name = "Samsung Smart TV";
SupportsAlbumArtInDidl = true;
Identification = new DeviceIdentification
{
ModelUrl = "samsung.com"
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
AudioCodec = "ac3",
VideoCodec = "h264",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "mp3,ac3,wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "mp3,ac3,dca",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg4,mjpeg4",
AudioCodec = "mp3,ac3,dca,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "3gpp",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,he-aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpg,mpeg",
VideoCodec = "mpeg1video,mpeg2video,h264",
AudioCodec = "ac3,mp2,mp3,aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "vro,vob",
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,mp2,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg2video,h264,vc1",
AudioCodec = "ac3,aac,mp3,eac3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3",
AudioCodec = "wmav2,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg2video",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "30720000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg4",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "8192000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "37500000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "wmv2,wmv3,vc1",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "25600000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3,wmav2,dca,aac,mp3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "mkv",
MimeType = "video/x-mkv",
Type = DlnaProfileType.Video
}
};
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,286 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SonyBravia2010Profile : DefaultProfile
{
public SonyBravia2010Profile()
{
Name = "Sony Bravia (2010)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[EHLNPB]X\d[01]\d.*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[EHLNPB]X\d[01]\d.*",
Match = HeaderMatchType.Regex
}
}
};
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
ProtocolInfo =
"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "ts",
VideoCodec="mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "mpeg",
VideoCodec="mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg2video",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac"
}
}
}
};
}
}
}

View File

@ -0,0 +1,304 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SonyBravia2011Profile : DefaultProfile
{
public SonyBravia2011Profile()
{
Name = "Sony Bravia (2011)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}([A-Z]X\d2\d|CX400).*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}([A-Z]X\d2\d|CX400).*",
Match = HeaderMatchType.Regex
}
}
};
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "ts",
VideoCodec="mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "mpeg",
VideoCodec="mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg2video",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "20000000"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac"
}
}
}
};
}
}
}

View File

@ -0,0 +1,246 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SonyBravia2012Profile : DefaultProfile
{
public SonyBravia2012Profile()
{
Name = "Sony Bravia (2012)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[A-Z]X\d5(\d|G).*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[A-Z]X\d5(\d|G).*",
Match = HeaderMatchType.Regex
}
}
};
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "ts",
VideoCodec="mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "mpeg",
VideoCodec="mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3",
Conditions = new[]
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6"
}
}
}
};
}
}
}

View File

@ -0,0 +1,264 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SonyBravia2013Profile : DefaultProfile
{
public SonyBravia2013Profile()
{
Name = "Sony Bravia (2013)";
Identification = new DeviceIdentification
{
FriendlyName = @"KDL-\d{2}[WR][5689]\d{2}A.*",
Manufacturer = "Sony",
Headers = new[]
{
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @".*KDL-\d{2}[WR][5689]\d{2}A.*",
Match = HeaderMatchType.Regex
}
}
};
ModelName = "Windows Media Player Sharing";
ModelNumber = "3.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
SonyAggregationFlags = "10";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,aac",
Type = DlnaProfileType.Video,
EnableMpegtsM2TsMode = true
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "ac3,eac3,aac,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "ts",
VideoCodec = "mpeg2video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4",
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mov",
VideoCodec = "h264,mpeg4,mjpeg",
AudioCodec = "ac3,eac3,aac,mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mkv",
VideoCodec = "h264,mpeg4,vp8",
AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,eac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mjpeg",
AudioCodec = "pcm",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mpeg",
VideoCodec = "mpeg2video,mpeg1video",
AudioCodec = "mp3,mp2",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "aac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "wav",
AudioCodec = "pcm",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="192"},
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoTimestamp, Value="1"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/mpeg",
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
Type = DlnaProfileType.Video,
Conditions = new []
{
new ProfileCondition{ Condition= ProfileConditionType.Equals, Property= ProfileConditionValue.VideoPacketLength, Value="188"}
}
},
new MediaProfile
{
Container = "ts",
VideoCodec="h264",
AudioCodec="ac3,aac,mp3",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "ts",
VideoCodec="mpeg2video",
MimeType = "video/vnd.dlna.mpeg-tts",
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "mpeg",
VideoCodec="mpeg1video,mpeg2video",
MimeType = "video/mpeg",
OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL",
Type = DlnaProfileType.Video
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
}
}
}

View File

@ -0,0 +1,233 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class SonyPs3Profile : DefaultProfile
{
public SonyPs3Profile()
{
Name = "Sony Bravia (2010)";
Identification = new DeviceIdentification
{
Headers = new[]
{
new HttpHeaderInfo
{
Name = "User-Agent",
Value = @"PLAYSTATION 3",
Match = HeaderMatchType.Substring
},
new HttpHeaderInfo
{
Name = "X-AV-Client-Info",
Value = @"PLAYSTATION 3",
Match = HeaderMatchType.Substring
}
}
};
SonyAggregationFlags = "10";
XDlnaDoc = "DMS-1.50";
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "mp3",
Type = DlnaProfileType.Video
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioBitrate,
Value = "640000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "wmapro",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
},
new ProfileCondition
{
Condition = ProfileConditionType.NotEquals,
Property = ProfileConditionValue.AudioProfile,
Value = "he-aac"
}
}
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "mp4,mov",
AudioCodec="aac",
MimeType = "video/mp4",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "avi",
MimeType = "video/divx",
OrgPn="AVI",
Type = DlnaProfileType.Video
},
new MediaProfile
{
Container = "wav",
MimeType = "audio/wav",
Type = DlnaProfileType.Audio
}
};
}
}
}

View File

@ -0,0 +1,241 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class WdtvLiveProfile : DefaultProfile
{
public WdtvLiveProfile()
{
Name = "WDTV Live";
TimelineOffsetSeconds = 5;
IgnoreTranscodeByteRangeRequests = true;
Identification = new DeviceIdentification
{
ModelName = "WD TV HD Live",
Headers = new []
{
new HttpHeaderInfo {Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring},
new HttpHeaderInfo
{
Name = "User-Agent",
Value = "ALPHA Networks",
Match = HeaderMatchType.Substring
}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
Type = DlnaProfileType.Audio,
AudioCodec = "mp3"
},
new TranscodingProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
VideoCodec = "h264",
AudioCodec = "aac",
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "avi",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Container = "mpeg",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video",
AudioCodec = "ac3,dca,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Container = "mkv",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1",
AudioCodec = "ac3,dca,aac,mp2,mp3,pcm"
},
new DirectPlayProfile
{
Container = "ts",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
AudioCodec = "ac3,dca,mp2,mp3"
},
new DirectPlayProfile
{
Container = "mp4,mov",
Type = DlnaProfileType.Video,
VideoCodec = "h264,mpeg4",
AudioCodec = "ac3,aac,mp2,mp3"
},
new DirectPlayProfile
{
Container = "asf",
Type = DlnaProfileType.Video,
VideoCodec = "vc1",
AudioCodec = "wmav2,wmapro"
},
new DirectPlayProfile
{
Container = "asf",
Type = DlnaProfileType.Video,
VideoCodec = "mpeg2video",
AudioCodec = "mp2,ac3"
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp2,mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp4",
AudioCodec = "mp4",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "flac",
AudioCodec = "flac",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "ogg",
AudioCodec = "vorbis",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Type = DlnaProfileType.Photo,
Container = "jpeg,png,gif,bmp,tiff"
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "ts",
OrgPn = "MPEG_TS_SD_NA",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41"
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "2"
}
}
}
};
}
}
}

View File

@ -0,0 +1,312 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class Xbox360Profile : DefaultProfile
{
public Xbox360Profile()
{
Name = "Xbox 360";
ModelName = "Windows Media Player Sharing";
ModelNumber = "12.0";
ModelUrl = "http://www.microsoft.com/";
Manufacturer = "Microsoft Corporation";
ManufacturerUrl = "http://www.microsoft.com/";
XDlnaDoc = "DMS-1.50";
TimelineOffsetSeconds = 40;
RequiresPlainFolders = true;
RequiresPlainVideoItems = true;
Identification = new DeviceIdentification
{
ModelName = "Xbox 360",
Headers = new []
{
new HttpHeaderInfo {Name = "User-Agent", Value = "Xbox", Match = HeaderMatchType.Substring},
new HttpHeaderInfo {Name = "User-Agent", Value = "Xenon", Match = HeaderMatchType.Substring}
}
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "asf",
VideoCodec = "wmv2",
AudioCodec = "wmav2",
Type = DlnaProfileType.Video,
TranscodeSeekInfo = TranscodeSeekInfo.Bytes,
EstimateContentLength = true,
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.MaxAudioChannels, Value = "6"},
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
},
new TranscodingProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "mpeg4",
AudioCodec = "ac3,mp3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "avi",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "mp4,mov",
VideoCodec = "h264,mpeg4",
AudioCodec = "aac,ac3",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
VideoCodec = "wmv2,wmv3,vc1",
AudioCodec = "wmav2,wmapro",
Type = DlnaProfileType.Video
},
new DirectPlayProfile
{
Container = "asf",
AudioCodec = "wmav2,wmapro,wmavoice",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new DirectPlayProfile
{
Container = "jpeg",
Type = DlnaProfileType.Photo
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "avi",
MimeType = "video/avi",
Type = DlnaProfileType.Video
}
};
ContainerProfiles = new[]
{
new ContainerProfile
{
Type = DlnaProfileType.Video,
Container = "mp4,mov",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Has64BitOffsets,
Value = "false",
IsRequired = false
}
}
},
new ContainerProfile
{
Type = DlnaProfileType.Photo,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
}
}
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "mpeg4",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1280"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "720"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "5120000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "h264",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "41",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "10240000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoCodec,
Codec = "wmv2,wmv3,vc1",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width,
Value = "1920"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height,
Value = "1080"
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoFramerate,
Value = "30",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "ac3,wmav2,wmapro",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
}
}
},
new CodecProfile
{
Type = CodecType.VideoAudioCodec,
Codec = "aac",
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.Equals,
Property = ProfileConditionValue.AudioProfile,
Value = "lc",
IsRequired = false
}
}
}
};
}
}
}

View File

@ -0,0 +1,54 @@
using MediaBrowser.Controller.Dlna;
namespace MediaBrowser.Dlna.Profiles
{
public class XboxOneProfile : DefaultProfile
{
public XboxOneProfile()
{
Name = "Xbox One";
Identification = new DeviceIdentification
{
ModelName = "Xbox One",
FriendlyName = "Xbox-SystemOS"
};
TranscodingProfiles = new[]
{
new TranscodingProfile
{
Container = "mp3",
AudioCodec = "mp3",
Type = DlnaProfileType.Audio
},
new TranscodingProfile
{
Container = "ts",
VideoCodec = "h264",
AudioCodec = "aac",
Type = DlnaProfileType.Video
}
};
DirectPlayProfiles = new[]
{
new DirectPlayProfile
{
Container = "mp3,wma",
Type = DlnaProfileType.Audio
}
};
MediaProfiles = new[]
{
new MediaProfile
{
Container = "avi",
MimeType = "video/x-msvideo",
Type = DlnaProfileType.Video
}
};
}
}
}

View File

@ -0,0 +1,115 @@
using MediaBrowser.Common;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
using System;
namespace MediaBrowser.Dlna.Server
{
public class DlnaServerEntryPoint : IServerEntryPoint
{
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private SsdpHandler _ssdpHandler;
private readonly IApplicationHost _appHost;
public DlnaServerEntryPoint(IServerConfigurationManager config, ILogManager logManager, IApplicationHost appHost)
{
_config = config;
_appHost = appHost;
_logger = logManager.GetLogger("DlnaServer");
}
public void Run()
{
_config.ConfigurationUpdated += ConfigurationUpdated;
//ReloadServer();
}
void ConfigurationUpdated(object sender, EventArgs e)
{
//ReloadServer();
}
private void ReloadServer()
{
var isStarted = _ssdpHandler != null;
if (_config.Configuration.DlnaOptions.EnableServer && !isStarted)
{
StartServer();
}
else if (!_config.Configuration.DlnaOptions.EnableServer && isStarted)
{
DisposeServer();
}
}
private readonly object _syncLock = new object();
private void StartServer()
{
var signature = GenerateServerSignature();
lock (_syncLock)
{
try
{
_ssdpHandler = new SsdpHandler(_logger, _config, signature);
}
catch (Exception ex)
{
_logger.ErrorException("Error starting Dlna server", ex);
}
}
}
private void DisposeServer()
{
lock (_syncLock)
{
if (_ssdpHandler != null)
{
try
{
_ssdpHandler.Dispose();
}
catch (Exception ex)
{
_logger.ErrorException("Error disposing Dlna server", ex);
}
_ssdpHandler = null;
}
}
}
private string GenerateServerSignature()
{
var os = Environment.OSVersion;
var pstring = os.Platform.ToString();
switch (os.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
pstring = "WIN";
break;
}
return String.Format(
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
pstring,
IntPtr.Size * 8,
os.Version.Major,
os.Version.Minor,
_appHost.ApplicationVersion
);
}
public void Dispose()
{
DisposeServer();
}
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace MediaBrowser.Dlna.Server
{
public class Headers : IDictionary<string, string>
{
private readonly bool _asIs = false;
private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
protected Headers(bool asIs)
{
_asIs = asIs;
}
public Headers()
: this(asIs: false)
{
}
public int Count
{
get
{
return _dict.Count;
}
}
public string HeaderBlock
{
get
{
var hb = new StringBuilder();
foreach (var h in this)
{
hb.AppendFormat("{0}: {1}\r\n", h.Key, h.Value);
}
return hb.ToString();
}
}
public Stream HeaderStream
{
get
{
return new MemoryStream(Encoding.ASCII.GetBytes(HeaderBlock));
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public ICollection<string> Keys
{
get
{
return _dict.Keys;
}
}
public ICollection<string> Values
{
get
{
return _dict.Values;
}
}
public string this[string key]
{
get
{
return _dict[Normalize(key)];
}
set
{
_dict[Normalize(key)] = value;
}
}
private string Normalize(string header)
{
if (!_asIs)
{
header = header.ToLower();
}
header = header.Trim();
if (!Validator.IsMatch(header))
{
throw new ArgumentException("Invalid header: " + header);
}
return header;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _dict.GetEnumerator();
}
public void Add(KeyValuePair<string, string> item)
{
Add(item.Key, item.Value);
}
public void Add(string key, string value)
{
_dict.Add(Normalize(key), value);
}
public void Clear()
{
_dict.Clear();
}
public bool Contains(KeyValuePair<string, string> item)
{
var p = new KeyValuePair<string, string>(Normalize(item.Key), item.Value);
return _dict.Contains(p);
}
public bool ContainsKey(string key)
{
return _dict.ContainsKey(Normalize(key));
}
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return _dict.GetEnumerator();
}
public bool Remove(string key)
{
return _dict.Remove(Normalize(key));
}
public bool Remove(KeyValuePair<string, string> item)
{
return Remove(item.Key);
}
public override string ToString()
{
return string.Format("({0})", string.Join(", ", (from x in _dict
select string.Format("{0}={1}", x.Key, x.Value))));
}
public bool TryGetValue(string key, out string value)
{
return _dict.TryGetValue(Normalize(key), out value);
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MediaBrowser.Dlna.Server
{
public class RawHeaders : Headers
{
public RawHeaders()
: base(true)
{
}
}
}

View File

@ -0,0 +1,260 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MediaBrowser.Dlna.Server
{
public class SsdpHandler : IDisposable
{
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
private readonly string _serverSignature;
private bool _isDisposed = false;
const string SSDPAddr = "239.255.255.250";
const int SSDPPort = 1900;
private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort);
private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr);
private UdpClient _udpClient;
private readonly Dictionary<Guid, List<UpnpDevice>> _devices = new Dictionary<Guid, List<UpnpDevice>>();
public SsdpHandler(ILogger logger, IServerConfigurationManager config, string serverSignature)
{
_logger = logger;
_config = config;
_serverSignature = serverSignature;
Start();
}
private IEnumerable<UpnpDevice> Devices
{
get
{
UpnpDevice[] devs;
lock (_devices)
{
devs = _devices.Values.SelectMany(i => i).ToArray();
}
return devs;
}
}
private void Start()
{
_udpClient = new UdpClient();
_udpClient.Client.UseOnlyOverlappedIO = true;
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.ExclusiveAddressUse = false;
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, SSDPPort));
_udpClient.JoinMulticastGroup(_ssdpIp, 2);
_logger.Info("SSDP service started");
Receive();
}
private void Receive()
{
try
{
_udpClient.BeginReceive(ReceiveCallback, null);
}
catch (ObjectDisposedException)
{
}
}
private void ReceiveCallback(IAsyncResult result)
{
try
{
var endpoint = new IPEndPoint(IPAddress.None, SSDPPort);
var received = _udpClient.EndReceive(result, ref endpoint);
if (_config.Configuration.DlnaOptions.EnableDebugLogging)
{
_logger.Debug("{0} - SSDP Received a datagram", endpoint);
}
using (var reader = new StreamReader(new MemoryStream(received), Encoding.ASCII))
{
var proto = (reader.ReadLine() ?? string.Empty).Trim();
var method = proto.Split(new[] { ' ' }, 2)[0];
var headers = new Headers();
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
line = line.Trim();
if (string.IsNullOrEmpty(line))
{
break;
}
var parts = line.Split(new char[] { ':' }, 2);
headers[parts[0]] = parts[1].Trim();
}
if (_config.Configuration.DlnaOptions.EnableDebugLogging)
{
_logger.Debug("{0} - Datagram method: {1}", endpoint, method);
//_logger.Debug(headers);
}
if (string.Equals(method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
{
RespondToSearch(endpoint, headers["st"]);
}
}
}
catch (Exception ex)
{
_logger.ErrorException("Failed to read SSDP message", ex);
}
if (!_isDisposed)
{
Receive();
}
}
private void RespondToSearch(IPEndPoint endpoint, string req)
{
if (req == "ssdp:all")
{
req = null;
}
if (_config.Configuration.DlnaOptions.EnableDebugLogging)
{
_logger.Debug("RespondToSearch");
}
foreach (var d in Devices)
{
if (!string.IsNullOrEmpty(req) && req != d.Type)
{
continue;
}
SendSearchResponse(endpoint, d);
}
}
private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev)
{
var headers = new RawHeaders();
headers.Add("CACHE-CONTROL", "max-age = 600");
headers.Add("DATE", DateTime.Now.ToString("R"));
headers.Add("EXT", "");
headers.Add("LOCATION", dev.Descriptor.ToString());
headers.Add("SERVER", _serverSignature);
headers.Add("ST", dev.Type);
headers.Add("USN", dev.USN);
SendDatagram(endpoint, String.Format("HTTP/1.1 200 OK\r\n{0}\r\n", headers.HeaderBlock), false);
_logger.Info("{1} - Responded to a {0} request", dev.Type, endpoint);
}
private void SendDatagram(IPEndPoint endpoint, string msg, bool sticky)
{
if (_isDisposed)
{
return;
}
//var dgram = new Datagram(endpoint, msg, sticky);
//if (messageQueue.Count == 0)
//{
// dgram.Send();
//}
//messageQueue.Enqueue(dgram);
//queueTimer.Enabled = true;
}
private void NotifyAll()
{
_logger.Debug("NotifyAll");
foreach (var d in Devices)
{
NotifyDevice(d, "alive", false);
}
}
private void NotifyDevice(UpnpDevice dev, string type, bool sticky)
{
_logger.Debug("NotifyDevice");
var headers = new RawHeaders();
headers.Add("HOST", "239.255.255.250:1900");
headers.Add("CACHE-CONTROL", "max-age = 600");
headers.Add("LOCATION", dev.Descriptor.ToString());
headers.Add("SERVER", _serverSignature);
headers.Add("NTS", "ssdp:" + type);
headers.Add("NT", dev.Type);
headers.Add("USN", dev.USN);
SendDatagram(_ssdpEndp, String.Format("NOTIFY * HTTP/1.1\r\n{0}\r\n", headers.HeaderBlock), sticky);
_logger.Debug("{0} said {1}", dev.USN, type);
}
private void RegisterNotification(Guid UUID, Uri Descriptor)
{
List<UpnpDevice> list;
lock (_devices)
{
if (!_devices.TryGetValue(UUID, out list))
{
_devices.Add(UUID, list = new List<UpnpDevice>());
}
}
foreach (var t in new[] { "upnp:rootdevice", "urn:schemas-upnp-org:device:MediaServer:1", "urn:schemas-upnp-org:service:ContentDirectory:1", "uuid:" + UUID })
{
list.Add(new UpnpDevice(UUID, t, Descriptor));
}
NotifyAll();
_logger.Debug("Registered mount {0}", UUID);
}
internal void UnregisterNotification(Guid UUID)
{
List<UpnpDevice> dl;
lock (_devices)
{
if (!_devices.TryGetValue(UUID, out dl))
{
return;
}
_devices.Remove(UUID);
}
foreach (var d in dl)
{
NotifyDevice(d, "byebye", true);
}
_logger.Debug("Unregistered mount {0}", UUID);
}
public void Dispose()
{
_isDisposed = true;
//while (messageQueue.Count != 0)
//{
// datagramPosted.WaitOne();
//}
_udpClient.DropMulticastGroup(_ssdpIp);
_udpClient.Close();
//notificationTimer.Enabled = false;
//queueTimer.Enabled = false;
//notificationTimer.Dispose();
//queueTimer.Dispose();
//datagramPosted.Dispose();
}
}
}

View File

@ -0,0 +1,28 @@
using System;
namespace MediaBrowser.Dlna.Server
{
public sealed class UpnpDevice
{
public readonly Uri Descriptor;
public readonly string Type;
public readonly string USN;
public readonly Guid Uuid;
public UpnpDevice(Guid aUuid, string aType, Uri aDescriptor)
{
Uuid = aUuid;
Type = aType;
Descriptor = aDescriptor;
if (Type.StartsWith("uuid:"))
{
USN = Type;
}
else
{
USN = String.Format("uuid:{0}::{1}", Uuid.ToString(), Type);
}
}
}
}

View File

@ -1030,7 +1030,7 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="timer">The timer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task CreateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken);
Task CreateLiveTvTimerAsync(BaseTimerInfoDto timer, CancellationToken cancellationToken);
/// <summary>
/// Updates the live tv timer asynchronous.

View File

@ -4,11 +4,15 @@ namespace MediaBrowser.Model.Configuration
public class DlnaOptions
{
public bool EnablePlayTo { get; set; }
public bool EnablePlayToDebugLogging { get; set; }
public bool EnableServer { get; set; }
public bool EnableDebugLogging { get; set; }
public int ClientDiscoveryIntervalSeconds { get; set; }
public DlnaOptions()
{
EnablePlayTo = true;
EnableServer = true;
ClientDiscoveryIntervalSeconds = 60;
}
}
}

View File

@ -10,7 +10,7 @@
/// Omit to copy
/// </summary>
/// <value>The video codec.</value>
public VideoCodecs? VideoCodec { get; set; }
public string VideoCodec { get; set; }
/// <summary>
/// Gets or sets the video bit rate.
@ -113,7 +113,7 @@
/// Omit to copy the original stream
/// </summary>
/// <value>The audio encoding format.</value>
public AudioCodecs? AudioCodec { get; set; }
public string AudioCodec { get; set; }
/// <summary>
/// Gets or sets the item id.
@ -158,68 +158,4 @@
/// <value>The device id.</value>
public string DeviceId { get; set; }
}
/// <summary>
/// These are the codecs the api is capable of encoding to
/// </summary>
public enum AudioCodecs
{
/// <summary>
/// The aac
/// </summary>
Aac,
/// <summary>
/// The MP3
/// </summary>
Mp3,
/// <summary>
/// The vorbis
/// </summary>
Vorbis,
/// <summary>
/// The wma
/// </summary>
Wma,
/// <summary>
/// The copy
/// </summary>
Copy
}
/// <summary>
/// Enum VideoCodecs
/// </summary>
public enum VideoCodecs
{
H263,
/// <summary>
/// The H264
/// </summary>
H264,
/// <summary>
/// The mpeg4
/// </summary>
Mpeg4,
/// <summary>
/// The theora
/// </summary>
Theora,
/// <summary>
/// The VPX
/// </summary>
Vpx,
/// <summary>
/// The WMV
/// </summary>
Wmv,
/// <summary>
/// The copy
/// </summary>
Copy
}
}

View File

@ -1,80 +1,14 @@
using System;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.Serialization;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.LiveTv
{
[DebuggerDisplay("Name = {Name}")]
public class SeriesTimerInfoDto : INotifyPropertyChanged
public class SeriesTimerInfoDto : BaseTimerInfoDto
{
/// <summary>
/// Id of the recording.
/// </summary>
public string Id { get; set; }
/// <summary>
/// Gets or sets the external identifier.
/// </summary>
/// <value>The external identifier.</value>
public string ExternalId { get; set; }
/// <summary>
/// ChannelId of the recording.
/// </summary>
public string ChannelId { get; set; }
/// <summary>
/// Gets or sets the name of the service.
/// </summary>
/// <value>The name of the service.</value>
public string ServiceName { get; set; }
/// <summary>
/// Gets or sets the external channel identifier.
/// </summary>
/// <value>The external channel identifier.</value>
public string ExternalChannelId { get; set; }
/// <summary>
/// ChannelName of the recording.
/// </summary>
public string ChannelName { get; set; }
/// <summary>
/// Gets or sets the program identifier.
/// </summary>
/// <value>The program identifier.</value>
public string ProgramId { get; set; }
/// <summary>
/// Gets or sets the external program identifier.
/// </summary>
/// <value>The external program identifier.</value>
public string ExternalProgramId { get; set; }
/// <summary>
/// Name of the recording.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Description of the recording.
/// </summary>
public string Overview { get; set; }
/// <summary>
/// The start date of the recording, in UTC.
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// The end date of the recording, in UTC.
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [record any time].
/// </summary>
@ -105,36 +39,6 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The day pattern.</value>
public DayPattern? DayPattern { get; set; }
/// <summary>
/// Gets or sets the priority.
/// </summary>
/// <value>The priority.</value>
public int Priority { get; set; }
/// <summary>
/// Gets or sets the pre padding seconds.
/// </summary>
/// <value>The pre padding seconds.</value>
public int PrePaddingSeconds { get; set; }
/// <summary>
/// Gets or sets the post padding seconds.
/// </summary>
/// <value>The post padding seconds.</value>
public int PostPaddingSeconds { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is pre padding required.
/// </summary>
/// <value><c>true</c> if this instance is pre padding required; otherwise, <c>false</c>.</value>
public bool IsPrePaddingRequired { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is post padding required.
/// </summary>
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
public bool IsPostPaddingRequired { get; set; }
/// <summary>
/// Gets or sets the image tags.
/// </summary>
@ -156,7 +60,5 @@ namespace MediaBrowser.Model.LiveTv
ImageTags = new Dictionary<ImageType, Guid>();
Days = new List<DayOfWeek>();
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

View File

@ -3,8 +3,47 @@ using System.ComponentModel;
namespace MediaBrowser.Model.LiveTv
{
public class TimerInfoDto : INotifyPropertyChanged
public class TimerInfoDto : BaseTimerInfoDto
{
/// <summary>
/// Gets or sets the status.
/// </summary>
/// <value>The status.</value>
public RecordingStatus Status { get; set; }
/// <summary>
/// Gets or sets the series timer identifier.
/// </summary>
/// <value>The series timer identifier.</value>
public string SeriesTimerId { get; set; }
/// <summary>
/// Gets or sets the external series timer identifier.
/// </summary>
/// <value>The external series timer identifier.</value>
public string ExternalSeriesTimerId { get; set; }
/// <summary>
/// Gets or sets the run time ticks.
/// </summary>
/// <value>The run time ticks.</value>
public long? RunTimeTicks { get; set; }
/// <summary>
/// Gets or sets the program information.
/// </summary>
/// <value>The program information.</value>
public ProgramInfoDto ProgramInfo { get; set; }
}
public class BaseTimerInfoDto : INotifyPropertyChanged
{
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Id of the recording.
/// </summary>
@ -32,12 +71,6 @@ namespace MediaBrowser.Model.LiveTv
/// </summary>
public string ChannelName { get; set; }
/// <summary>
/// Gets or sets the name of the service.
/// </summary>
/// <value>The name of the service.</value>
public string ServiceName { get; set; }
/// <summary>
/// Gets or sets the program identifier.
/// </summary>
@ -71,22 +104,16 @@ namespace MediaBrowser.Model.LiveTv
public DateTime EndDate { get; set; }
/// <summary>
/// Gets or sets the status.
/// Gets or sets the name of the service.
/// </summary>
/// <value>The status.</value>
public RecordingStatus Status { get; set; }
/// <value>The name of the service.</value>
public string ServiceName { get; set; }
/// <summary>
/// Gets or sets the series timer identifier.
/// Gets or sets the priority.
/// </summary>
/// <value>The series timer identifier.</value>
public string SeriesTimerId { get; set; }
/// <summary>
/// Gets or sets the external series timer identifier.
/// </summary>
/// <value>The external series timer identifier.</value>
public string ExternalSeriesTimerId { get; set; }
/// <value>The priority.</value>
public int Priority { get; set; }
/// <summary>
/// Gets or sets the pre padding seconds.
@ -111,28 +138,5 @@ namespace MediaBrowser.Model.LiveTv
/// </summary>
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
public bool IsPostPaddingRequired { get; set; }
/// <summary>
/// Gets or sets the run time ticks.
/// </summary>
/// <value>The run time ticks.</value>
public long? RunTimeTicks { get; set; }
/// <summary>
/// Gets or sets the priority.
/// </summary>
/// <value>The priority.</value>
public int Priority { get; set; }
/// <summary>
/// Gets or sets the program information.
/// </summary>
/// <value>The program information.</value>
public ProgramInfoDto ProgramInfo { get; set; }
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
}
}

View File

@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
CreateRules(device);
}
catch (Exception ex)
catch (Exception)
{
//_logger.ErrorException("Error creating port forwarding rules", ex);
}

View File

@ -266,7 +266,7 @@ namespace MediaBrowser.ServerApplication
{
MigrateUserFolders();
}
catch (IOException ex)
catch (IOException)
{
}
@ -498,7 +498,7 @@ namespace MediaBrowser.ServerApplication
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager);
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, JsonSerializer);
RegisterSingleInstance<IDlnaManager>(dlnaManager);
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);

View File

@ -4029,7 +4029,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
self.createPackageReview = function (review) {
var url = self.getUrl("PackageReviews/" + review.id, review);
var url = self.getUrl("Packages/Reviews/" + review.id, review);
return self.ajax({
type: "POST",
@ -4058,7 +4058,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
options.ForceTitle = true;
}
var url = self.getUrl("PackageReviews/" + packageId, options);
var url = self.getUrl("Packages/" + packageId + "Reviews", options);
return self.ajax({
type: "GET",

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.247" targetFramework="net45" />
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.248" targetFramework="net45" />
</packages>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
<version>3.0.343</version>
<version>3.0.345</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.343" />
<dependency id="MediaBrowser.Common" version="3.0.345" />
<dependency id="NLog" version="2.1.0" />
<dependency id="SimpleInjector" version="2.4.1" />
<dependency id="sharpcompress" version="0.10.2" />

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
<version>3.0.343</version>
<version>3.0.345</version>
<title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
<version>3.0.343</version>
<version>3.0.345</version>
<title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.343" />
<dependency id="MediaBrowser.Common" version="3.0.345" />
</dependencies>
</metadata>
<files>