Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
38a0af6e86
|
@ -10,8 +10,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetCultures
|
/// Class GetCultures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Localization/Cultures", "GET")]
|
[Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")]
|
||||||
[Api(Description = "Gets known cultures")]
|
|
||||||
public class GetCultures : IReturn<List<CultureDto>>
|
public class GetCultures : IReturn<List<CultureDto>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -19,8 +18,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetCountries
|
/// Class GetCountries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Localization/Countries", "GET")]
|
[Route("/Localization/Countries", "GET", Summary = "Gets known countries")]
|
||||||
[Api(Description = "Gets known countries")]
|
|
||||||
public class GetCountries : IReturn<List<CountryInfo>>
|
public class GetCountries : IReturn<List<CountryInfo>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -28,8 +26,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class ParentalRatings
|
/// Class ParentalRatings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Localization/ParentalRatings", "GET")]
|
[Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")]
|
||||||
[Api(Description = "Gets known parental ratings")]
|
|
||||||
public class GetParentalRatings : IReturn<List<ParentalRating>>
|
public class GetParentalRatings : IReturn<List<ParentalRating>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,9 @@ namespace MediaBrowser.Api.Movies
|
||||||
|
|
||||||
public object Get(GetMovieRecommendations request)
|
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 = user.RootFolder.GetRecursiveChildren(user).OfType<Movie>().ToList();
|
||||||
var movies = folder.RecursiveChildren.OfType<Movie>().ToList();
|
|
||||||
|
|
||||||
var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
|
var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ using ServiceStack;
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
[Route("/News/Product", "GET")]
|
[Route("/News/Product", "GET", Summary = "Gets the latest product news.")]
|
||||||
[Api(Description = "Gets the latest product news.")]
|
|
||||||
public class GetProductNews : IReturn<QueryResult<NewsItem>>
|
public class GetProductNews : IReturn<QueryResult<NewsItem>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -23,7 +22,7 @@ namespace MediaBrowser.Api
|
||||||
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int? Limit { get; set; }
|
public int? Limit { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NewsService : BaseApiService
|
public class NewsService : BaseApiService
|
||||||
{
|
{
|
||||||
private readonly INewsService _newsService;
|
private readonly INewsService _newsService;
|
||||||
|
@ -37,8 +36,8 @@ namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
var result = _newsService.GetProductNews(new NewsQuery
|
var result = _newsService.GetProductNews(new NewsQuery
|
||||||
{
|
{
|
||||||
StartIndex = request.StartIndex,
|
StartIndex = request.StartIndex,
|
||||||
Limit = request.Limit
|
Limit = request.Limit
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
using MediaBrowser.Controller.Notifications;
|
using MediaBrowser.Controller.Notifications;
|
||||||
using MediaBrowser.Model.Notifications;
|
using MediaBrowser.Model.Notifications;
|
||||||
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ServiceStack;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
[Route("/Notifications/{UserId}", "GET")]
|
[Route("/Notifications/{UserId}", "GET", Summary = "Gets notifications")]
|
||||||
[Api(Description = "Gets notifications")]
|
|
||||||
public class GetNotifications : IReturn<NotificationResult>
|
public class GetNotifications : IReturn<NotificationResult>
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[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; }
|
public int? Limit { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Notifications/{UserId}/Summary", "GET")]
|
[Route("/Notifications/{UserId}/Summary", "GET", Summary = "Gets a notification summary for a user")]
|
||||||
[Api(Description = "Gets a notification summary for a user")]
|
|
||||||
public class GetNotificationsSummary : IReturn<NotificationsSummary>
|
public class GetNotificationsSummary : IReturn<NotificationsSummary>
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
public Guid UserId { get; set; }
|
public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Notifications/{UserId}", "POST")]
|
[Route("/Notifications/{UserId}", "POST", Summary = "Adds a notifications")]
|
||||||
[Api(Description = "Adds a notifications")]
|
|
||||||
public class AddUserNotification : IReturn<Notification>
|
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")]
|
[ApiMember(Name = "Id", Description = "The Id of the new notification. If unspecified one will be provided.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||||
|
@ -61,9 +58,8 @@ namespace MediaBrowser.Api
|
||||||
[ApiMember(Name = "Level", Description = "The notification level", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
[ApiMember(Name = "Level", Description = "The notification level", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
|
||||||
public NotificationLevel Level { get; set; }
|
public NotificationLevel Level { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Notifications/{UserId}/Read", "POST")]
|
[Route("/Notifications/{UserId}/Read", "POST", Summary = "Marks notifications as read")]
|
||||||
[Api(Description = "Marks notifications as read")]
|
|
||||||
public class MarkRead : IReturnVoid
|
public class MarkRead : IReturnVoid
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
[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; }
|
public string Ids { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Notifications/{UserId}/Unread", "POST")]
|
[Route("/Notifications/{UserId}/Unread", "POST", Summary = "Marks notifications as unread")]
|
||||||
[Api(Description = "Marks notifications as unread")]
|
|
||||||
public class MarkUnread : IReturnVoid
|
public class MarkUnread : IReturnVoid
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
using System.Collections.Generic;
|
using MediaBrowser.Common.Constants;
|
||||||
using System.Globalization;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MediaBrowser.Common.Constants;
|
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class InstallPackage
|
/// Class InstallPackage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/PackageReviews/{Id}", "POST")]
|
[Route("/Packages/Reviews/{Id}", "POST", Summary = "Creates or updates a package review")]
|
||||||
[Api(("Creates or updates a package review"))]
|
|
||||||
public class CreateReviewRequest : IReturnVoid
|
public class CreateReviewRequest : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,8 +56,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class InstallPackage
|
/// Class InstallPackage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/PackageReviews/{Id}", "GET")]
|
[Route("/Packages/{Id}/Reviews", "GET", Summary = "Gets reviews for a package")]
|
||||||
[Api(("Retrieve reviews for a package"))]
|
|
||||||
public class ReviewRequest : IReturn<List<PackageReviewInfo>>
|
public class ReviewRequest : IReturn<List<PackageReviewInfo>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -114,7 +112,7 @@ namespace MediaBrowser.Api
|
||||||
public object Get(ReviewRequest request)
|
public object Get(ReviewRequest request)
|
||||||
{
|
{
|
||||||
var parms = "?id=" + request.Id;
|
var parms = "?id=" + request.Id;
|
||||||
|
|
||||||
if (request.MaxRating > 0)
|
if (request.MaxRating > 0)
|
||||||
{
|
{
|
||||||
parms += "&max=" + request.MaxRating;
|
parms += "&max=" + request.MaxRating;
|
||||||
|
@ -132,7 +130,7 @@ namespace MediaBrowser.Api
|
||||||
parms += "&title=true";
|
parms += "&title=true";
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = _httpClient.Get(Constants.MbAdminUrl + "/service/packageReview/retrieve"+parms, CancellationToken.None).Result;
|
var result = _httpClient.Get(Constants.MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None).Result;
|
||||||
|
|
||||||
var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
|
var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetPackage
|
/// Class GetPackage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Packages/{Name}", "GET")]
|
[Route("/Packages/{Name}", "GET", Summary = "Gets a package, by name or assembly guid")]
|
||||||
[Api(("Gets a package, by name or assembly guid"))]
|
|
||||||
public class GetPackage : IReturn<PackageInfo>
|
public class GetPackage : IReturn<PackageInfo>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -36,8 +35,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetPackages
|
/// Class GetPackages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Packages", "GET")]
|
[Route("/Packages", "GET", Summary = "Gets available packages")]
|
||||||
[Api(("Gets available packages"))]
|
|
||||||
public class GetPackages : IReturn<List<PackageInfo>>
|
public class GetPackages : IReturn<List<PackageInfo>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,8 +55,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetPackageVersionUpdates
|
/// Class GetPackageVersionUpdates
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Packages/Updates", "GET")]
|
[Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")]
|
||||||
[Api(("Gets available package updates for currently installed packages"))]
|
|
||||||
public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>>
|
public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -72,8 +69,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class InstallPackage
|
/// Class InstallPackage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Packages/Installed/{Name}", "POST")]
|
[Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")]
|
||||||
[Api(("Installs a package"))]
|
|
||||||
public class InstallPackage : IReturnVoid
|
public class InstallPackage : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -108,8 +104,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class CancelPackageInstallation
|
/// Class CancelPackageInstallation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Packages/Installing/{Id}", "DELETE")]
|
[Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")]
|
||||||
[Api(("Cancels a package installation"))]
|
|
||||||
public class CancelPackageInstallation : IReturnVoid
|
public class CancelPackageInstallation : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -9,7 +9,6 @@ using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Dto;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Library;
|
using MediaBrowser.Model.Library;
|
||||||
|
@ -735,16 +734,23 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
if (audioStream != null)
|
if (audioStream != null)
|
||||||
{
|
{
|
||||||
if (audioStream.Channels > 2 && request.AudioCodec.HasValue)
|
if (audioStream.Channels > 2 && string.Equals(request.AudioCodec, "wma", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (request.AudioCodec.Value == AudioCodecs.Wma)
|
// wmav2 currently only supports two channel output
|
||||||
{
|
return 2;
|
||||||
// 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;
|
return request.AudioChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,26 +774,26 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var codec = request.AudioCodec;
|
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";
|
return "aac -strict experimental";
|
||||||
}
|
}
|
||||||
if (codec == AudioCodecs.Mp3)
|
if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "libmp3lame";
|
return "libmp3lame";
|
||||||
}
|
}
|
||||||
if (codec == AudioCodecs.Vorbis)
|
if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "libvorbis";
|
return "libvorbis";
|
||||||
}
|
}
|
||||||
if (codec == AudioCodecs.Wma)
|
if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "wmav2";
|
return "wmav2";
|
||||||
}
|
}
|
||||||
|
|
||||||
return codec.ToString().ToLower();
|
return codec.ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "copy";
|
return "copy";
|
||||||
|
@ -802,26 +808,26 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var codec = request.VideoCodec;
|
var codec = request.VideoCodec;
|
||||||
|
|
||||||
if (codec.HasValue)
|
if (!string.IsNullOrEmpty(codec))
|
||||||
{
|
{
|
||||||
if (codec == VideoCodecs.H264)
|
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "libx264";
|
return "libx264";
|
||||||
}
|
}
|
||||||
if (codec == VideoCodecs.Vpx)
|
if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "libvpx";
|
return "libvpx";
|
||||||
}
|
}
|
||||||
if (codec == VideoCodecs.Wmv)
|
if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "msmpeg4";
|
return "msmpeg4";
|
||||||
}
|
}
|
||||||
if (codec == VideoCodecs.Theora)
|
if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "libtheora";
|
return "libtheora";
|
||||||
}
|
}
|
||||||
|
|
||||||
return codec.ToString().ToLower();
|
return codec.ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "copy";
|
return "copy";
|
||||||
|
@ -1201,77 +1207,81 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
request.DeviceId = val;
|
// Device profile name
|
||||||
}
|
}
|
||||||
else if (i == 1)
|
else if (i == 1)
|
||||||
{
|
{
|
||||||
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
request.DeviceId = val;
|
||||||
}
|
}
|
||||||
else if (i == 2)
|
else if (i == 2)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
request.MediaSourceId = val;
|
||||||
{
|
|
||||||
videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (i == 3)
|
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)
|
else if (i == 4)
|
||||||
|
{
|
||||||
|
if (videoRequest != null)
|
||||||
|
{
|
||||||
|
videoRequest.VideoCodec = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (i == 5)
|
||||||
|
{
|
||||||
|
request.AudioCodec = val;
|
||||||
|
}
|
||||||
|
else if (i == 6)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
|
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 5)
|
else if (i == 7)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
|
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 6)
|
else if (i == 8)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
|
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 7)
|
else if (i == 9)
|
||||||
{
|
{
|
||||||
request.AudioBitRate = int.Parse(val, UsCulture);
|
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)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
request.StartTimeTicks = long.Parse(val, UsCulture);
|
request.StartTimeTicks = long.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 10)
|
else if (i == 12)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.Profile = val;
|
videoRequest.Profile = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 11)
|
else if (i == 13)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.Level = val;
|
videoRequest.Level = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 12)
|
|
||||||
{
|
|
||||||
request.ForcedMimeType = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,7 +1307,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var url = Request.PathInfo;
|
var url = Request.PathInfo;
|
||||||
|
|
||||||
if (!request.AudioCodec.HasValue)
|
if (string.IsNullOrEmpty(request.AudioCodec))
|
||||||
{
|
{
|
||||||
request.AudioCodec = InferAudioCodec(url);
|
request.AudioCodec = InferAudioCodec(url);
|
||||||
}
|
}
|
||||||
|
@ -1425,7 +1435,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
if (!videoRequest.VideoCodec.HasValue)
|
if (string.IsNullOrEmpty(videoRequest.VideoCodec))
|
||||||
{
|
{
|
||||||
videoRequest.VideoCodec = InferVideoCodec(url);
|
videoRequest.VideoCodec = InferVideoCodec(url);
|
||||||
}
|
}
|
||||||
|
@ -1532,41 +1542,41 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url">The URL.</param>
|
/// <param name="url">The URL.</param>
|
||||||
/// <returns>System.Nullable{AudioCodecs}.</returns>
|
/// <returns>System.Nullable{AudioCodecs}.</returns>
|
||||||
private AudioCodecs? InferAudioCodec(string url)
|
private string InferAudioCodec(string url)
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(url);
|
var ext = Path.GetExtension(url);
|
||||||
|
|
||||||
if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Mp3;
|
return "mp3";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Aac;
|
return "aac";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Wma;
|
return "wma";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Vorbis;
|
return "vorbis";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Vorbis;
|
return "vorbis";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Vorbis;
|
return "vorbis";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Vorbis;
|
return "vorbis";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return AudioCodecs.Vorbis;
|
return "vorbis";
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -1577,28 +1587,28 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url">The URL.</param>
|
/// <param name="url">The URL.</param>
|
||||||
/// <returns>System.Nullable{VideoCodecs}.</returns>
|
/// <returns>System.Nullable{VideoCodecs}.</returns>
|
||||||
private VideoCodecs? InferVideoCodec(string url)
|
private string InferVideoCodec(string url)
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(url);
|
var ext = Path.GetExtension(url);
|
||||||
|
|
||||||
if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return VideoCodecs.Wmv;
|
return "wmv";
|
||||||
}
|
}
|
||||||
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
|
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))
|
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))
|
if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return VideoCodecs.H264;
|
return "h264";
|
||||||
}
|
}
|
||||||
|
|
||||||
return VideoCodecs.Copy;
|
return "copy";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,11 +91,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
var state = GetState(request, CancellationToken.None).Result;
|
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");
|
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");
|
throw new ArgumentException("An audio bitrate is required");
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,11 +136,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
|
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");
|
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");
|
throw new ArgumentException("An audio bitrate is required");
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,39 +50,49 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
var videoRequest = state.Request as VideoStreamRequest;
|
var videoRequest = state.Request as VideoStreamRequest;
|
||||||
|
|
||||||
// Try to infer based on the desired video codec
|
// 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)
|
if (state.IsInputVideo)
|
||||||
{
|
{
|
||||||
switch (videoRequest.VideoCodec.Value)
|
if (string.Equals(videoRequest.VideoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
case VideoCodecs.H264:
|
return ".ts";
|
||||||
return ".ts";
|
}
|
||||||
case VideoCodecs.Theora:
|
if (string.Equals(videoRequest.VideoCodec, "theora", StringComparison.OrdinalIgnoreCase))
|
||||||
return ".ogv";
|
{
|
||||||
case VideoCodecs.Vpx:
|
return ".ogv";
|
||||||
return ".webm";
|
}
|
||||||
case VideoCodecs.Wmv:
|
if (string.Equals(videoRequest.VideoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
|
||||||
return ".asf";
|
{
|
||||||
|
return ".webm";
|
||||||
|
}
|
||||||
|
if (string.Equals(videoRequest.VideoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return ".asf";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to infer based on the desired audio codec
|
// Try to infer based on the desired audio codec
|
||||||
if (state.Request.AudioCodec.HasValue)
|
if (!string.IsNullOrEmpty(state.Request.AudioCodec))
|
||||||
{
|
{
|
||||||
if (!state.IsInputVideo)
|
if (!state.IsInputVideo)
|
||||||
{
|
{
|
||||||
switch (state.Request.AudioCodec.Value)
|
if (string.Equals("aac", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
case AudioCodecs.Aac:
|
return ".aac";
|
||||||
return ".aac";
|
}
|
||||||
case AudioCodecs.Mp3:
|
if (string.Equals("mp3", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
||||||
return ".mp3";
|
{
|
||||||
case AudioCodecs.Vorbis:
|
return ".mp3";
|
||||||
return ".ogg";
|
}
|
||||||
case AudioCodecs.Wma:
|
if (string.Equals("vorbis", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
||||||
return ".wma";
|
{
|
||||||
|
return ".ogg";
|
||||||
|
}
|
||||||
|
if (string.Equals("wma", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return ".wma";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Model.Dto;
|
using ServiceStack;
|
||||||
using ServiceStack;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -26,7 +25,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The audio codec.</value>
|
/// <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")]
|
[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>
|
/// <summary>
|
||||||
/// Gets or sets the start time ticks.
|
/// 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")]
|
[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; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the audio sample rate.
|
/// Gets or sets the audio sample rate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -69,8 +71,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
public bool ThrowDebugError { get; set; }
|
public bool ThrowDebugError { get; set; }
|
||||||
|
|
||||||
public string Params { get; set; }
|
public string Params { get; set; }
|
||||||
|
|
||||||
public string ForcedMimeType { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VideoStreamRequest : StreamRequest
|
public class VideoStreamRequest : StreamRequest
|
||||||
|
@ -80,7 +80,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The video codec.</value>
|
/// <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")]
|
[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>
|
/// <summary>
|
||||||
/// Gets or sets the video bit rate.
|
/// Gets or sets the video bit rate.
|
||||||
|
|
|
@ -79,16 +79,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public string GetMimeType(string outputPath)
|
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);
|
return MimeTypes.GetMimeType(outputPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class Plugins
|
/// Class Plugins
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins", "GET")]
|
[Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
|
||||||
[Api(("Gets a list of currently installed plugins"))]
|
|
||||||
public class GetPlugins : IReturn<List<PluginInfo>>
|
public class GetPlugins : IReturn<List<PluginInfo>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -27,8 +26,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UninstallPlugin
|
/// Class UninstallPlugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins/{Id}", "DELETE")]
|
[Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")]
|
||||||
[Api(("Uninstalls a plugin"))]
|
|
||||||
public class UninstallPlugin : IReturnVoid
|
public class UninstallPlugin : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -42,8 +40,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetPluginConfiguration
|
/// Class GetPluginConfiguration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins/{Id}/Configuration", "GET")]
|
[Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")]
|
||||||
[Api(("Gets a plugin's configuration"))]
|
|
||||||
public class GetPluginConfiguration
|
public class GetPluginConfiguration
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -57,8 +54,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UpdatePluginConfiguration
|
/// Class UpdatePluginConfiguration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins/{Id}/Configuration", "POST")]
|
[Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")]
|
||||||
[Api(("Updates a plugin's configuration"))]
|
|
||||||
public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid
|
public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -78,8 +74,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetPluginSecurityInfo
|
/// Class GetPluginSecurityInfo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins/SecurityInfo", "GET")]
|
[Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information")]
|
||||||
[Api(("Gets plugin registration information"))]
|
|
||||||
public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo>
|
public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -87,14 +82,12 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UpdatePluginSecurityInfo
|
/// Class UpdatePluginSecurityInfo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Plugins/SecurityInfo", "POST")]
|
[Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information")]
|
||||||
[Api("Updates plugin registration information")]
|
|
||||||
public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid
|
public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Plugins/RegistrationRecords/{Name}", "GET")]
|
[Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature")]
|
||||||
[Api("Gets registration status for a feature")]
|
|
||||||
public class GetRegistrationStatus
|
public class GetRegistrationStatus
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
[ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||||
|
|
|
@ -39,6 +39,8 @@ namespace MediaBrowser.Api.ScheduledTasks
|
||||||
TaskManager = taskManager;
|
TaskManager = taskManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _lastResponseHadTasksRunning = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the data to send.
|
/// Gets the data to send.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -46,7 +48,25 @@ namespace MediaBrowser.Api.ScheduledTasks
|
||||||
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
|
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
|
||||||
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(object state)
|
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)
|
.OrderBy(i => i.Name)
|
||||||
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
.Select(ScheduledTaskHelpers.GetTaskInfo)
|
||||||
.Where(i => !i.IsHidden));
|
.Where(i => !i.IsHidden));
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
|
@ -8,6 +7,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Search;
|
using MediaBrowser.Model.Search;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -16,8 +16,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetSearchHints
|
/// Class GetSearchHints
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Search/Hints", "GET")]
|
[Route("/Search/Hints", "GET", Summary = "Gets search hints based on a search term")]
|
||||||
[Api(Description = "Gets search hints based on a search term")]
|
|
||||||
public class GetSearchHints : IReturn<SearchHintResult>
|
public class GetSearchHints : IReturn<SearchHintResult>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -66,7 +65,7 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
public string IncludeItemTypes { get; set; }
|
public string IncludeItemTypes { get; set; }
|
||||||
|
|
||||||
public GetSearchHints()
|
public GetSearchHints()
|
||||||
{
|
{
|
||||||
IncludeArtists = true;
|
IncludeArtists = true;
|
||||||
|
|
|
@ -14,8 +14,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetSessions
|
/// Class GetSessions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Sessions", "GET")]
|
[Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
|
||||||
[Api(("Gets a list of sessions"))]
|
|
||||||
public class GetSessions : IReturn<List<SessionInfoDto>>
|
public class GetSessions : IReturn<List<SessionInfoDto>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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")]
|
[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; }
|
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; }
|
public string DeviceId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class BrowseTo
|
/// Class BrowseTo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Sessions/{Id}/Viewing", "POST")]
|
[Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")]
|
||||||
[Api(("Instructs a session to browse to an item or view"))]
|
|
||||||
public class BrowseTo : IReturnVoid
|
public class BrowseTo : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -77,8 +75,7 @@ namespace MediaBrowser.Api
|
||||||
public string Context { get; set; }
|
public string Context { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Playing", "POST")]
|
[Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
|
||||||
[Api(("Instructs a session to play an item"))]
|
|
||||||
public class Play : IReturnVoid
|
public class Play : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -110,8 +107,7 @@ namespace MediaBrowser.Api
|
||||||
public PlayCommand PlayCommand { get; set; }
|
public PlayCommand PlayCommand { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Playing/{Command}", "POST")]
|
[Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
|
||||||
[Api(("Issues a playstate command to a client"))]
|
|
||||||
public class SendPlaystateCommand : IReturnVoid
|
public class SendPlaystateCommand : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -135,8 +131,7 @@ namespace MediaBrowser.Api
|
||||||
public PlaystateCommand Command { get; set; }
|
public PlaystateCommand Command { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/System/{Command}", "POST")]
|
[Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")]
|
||||||
[Api(("Issues a system command to a client"))]
|
|
||||||
public class SendSystemCommand : IReturnVoid
|
public class SendSystemCommand : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -154,8 +149,7 @@ namespace MediaBrowser.Api
|
||||||
public SystemCommand Command { get; set; }
|
public SystemCommand Command { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Message", "POST")]
|
[Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")]
|
||||||
[Api(("Issues a command to a client to display a message to the user"))]
|
|
||||||
public class SendMessageCommand : IReturnVoid
|
public class SendMessageCommand : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -175,8 +169,7 @@ namespace MediaBrowser.Api
|
||||||
public long? TimeoutMs { get; set; }
|
public long? TimeoutMs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Users/{UserId}", "POST")]
|
[Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")]
|
||||||
[Api(("Adds an additional user to a session"))]
|
|
||||||
public class AddUserToSession : IReturnVoid
|
public class AddUserToSession : IReturnVoid
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
[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; }
|
public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Users/{UserId}", "DELETE")]
|
[Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")]
|
||||||
[Api(("Removes an additional user from a session"))]
|
|
||||||
public class RemoveUserFromSession : IReturnVoid
|
public class RemoveUserFromSession : IReturnVoid
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
[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; }
|
public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Sessions/{Id}/Capabilities", "POST")]
|
[Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")]
|
||||||
[Api(("Updates capabilities for a device"))]
|
|
||||||
public class PostCapabilities : IReturnVoid
|
public class PostCapabilities : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -8,8 +8,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetSystemInfo
|
/// Class GetSystemInfo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/System/Info", "GET")]
|
[Route("/System/Info", "GET", Summary = "Gets information about the server")]
|
||||||
[Api(Description = "Gets information about the server")]
|
|
||||||
public class GetSystemInfo : IReturn<SystemInfo>
|
public class GetSystemInfo : IReturn<SystemInfo>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -18,18 +17,16 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class RestartApplication
|
/// Class RestartApplication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/System/Restart", "POST")]
|
[Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")]
|
||||||
[Api(("Restarts the application, if needed"))]
|
|
||||||
public class RestartApplication
|
public class RestartApplication
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/System/Shutdown", "POST")]
|
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
|
||||||
[Api(("Shuts down the application"))]
|
|
||||||
public class ShutdownApplication
|
public class ShutdownApplication
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class SystemInfoService
|
/// Class SystemInfoService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetNextUpEpisodes
|
/// Class GetNextUpEpisodes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Shows/NextUp", "GET")]
|
[Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")]
|
||||||
[Api(("Gets a list of next up episodes"))]
|
|
||||||
public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields
|
public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -53,8 +52,7 @@ namespace MediaBrowser.Api
|
||||||
public string SeriesId { get; set; }
|
public string SeriesId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Shows/Upcoming", "GET")]
|
[Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
|
||||||
[Api(("Gets a list of upcoming episodes"))]
|
|
||||||
public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasItemFields
|
public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasItemFields
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -86,14 +84,12 @@ namespace MediaBrowser.Api
|
||||||
public string Fields { get; set; }
|
public string Fields { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Shows/{Id}/Similar", "GET")]
|
[Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")]
|
||||||
[Api(Description = "Finds tv shows similar to a given one.")]
|
|
||||||
public class GetSimilarShows : BaseGetSimilarItemsFromItem
|
public class GetSimilarShows : BaseGetSimilarItemsFromItem
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Shows/{Id}/Episodes", "GET")]
|
[Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")]
|
||||||
[Api(Description = "Gets episodes for a tv season")]
|
|
||||||
public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields
|
public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -129,8 +125,7 @@ namespace MediaBrowser.Api
|
||||||
public string AdjacentTo { get; set; }
|
public string AdjacentTo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Shows/{Id}/Seasons", "GET")]
|
[Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
|
||||||
[Api(Description = "Gets seasons for a tv series")]
|
|
||||||
public class GetSeasons : IReturn<ItemsResult>, IHasItemFields
|
public class GetSeasons : IReturn<ItemsResult>, IHasItemFields
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -320,7 +315,7 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
})
|
})
|
||||||
.ThenByDescending(i =>i.Item2)
|
.ThenByDescending(i => i.Item2)
|
||||||
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
|
.ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
|
||||||
.Select(i => i.Item1);
|
.Select(i => i.Item1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetUsers
|
/// Class GetUsers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users", "GET")]
|
[Route("/Users", "GET", Summary = "Gets a list of users")]
|
||||||
[Api(Description = "Gets a list of users")]
|
|
||||||
public class GetUsers : IReturn<List<UserDto>>
|
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")]
|
[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; }
|
public bool? IsDisabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Users/Public", "GET")]
|
[Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
|
||||||
[Api(Description = "Gets a list of publicly visible users for display on a login screen.")]
|
|
||||||
public class GetPublicUsers : IReturn<List<UserDto>>
|
public class GetPublicUsers : IReturn<List<UserDto>>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -37,8 +35,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class GetUser
|
/// Class GetUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{Id}", "GET")]
|
[Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")]
|
||||||
[Api(Description = "Gets a user by Id")]
|
|
||||||
public class GetUser : IReturn<UserDto>
|
public class GetUser : IReturn<UserDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -52,8 +49,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class DeleteUser
|
/// Class DeleteUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{Id}", "DELETE")]
|
[Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")]
|
||||||
[Api(Description = "Deletes a user")]
|
|
||||||
public class DeleteUser : IReturnVoid
|
public class DeleteUser : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -67,8 +63,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class AuthenticateUser
|
/// Class AuthenticateUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{Id}/Authenticate", "POST")]
|
[Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")]
|
||||||
[Api(Description = "Authenticates a user")]
|
|
||||||
public class AuthenticateUser : IReturn<AuthenticationResult>
|
public class AuthenticateUser : IReturn<AuthenticationResult>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -89,8 +84,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class AuthenticateUser
|
/// Class AuthenticateUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/AuthenticateByName", "POST")]
|
[Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")]
|
||||||
[Api(Description = "Authenticates a user")]
|
|
||||||
public class AuthenticateUserByName : IReturn<AuthenticationResult>
|
public class AuthenticateUserByName : IReturn<AuthenticationResult>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -111,8 +105,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UpdateUserPassword
|
/// Class UpdateUserPassword
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{Id}/Password", "POST")]
|
[Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")]
|
||||||
[Api(Description = "Updates a user's password")]
|
|
||||||
public class UpdateUserPassword : IReturnVoid
|
public class UpdateUserPassword : IReturnVoid
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -143,8 +136,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class UpdateUser
|
/// Class UpdateUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users/{Id}", "POST")]
|
[Route("/Users/{Id}", "POST", Summary = "Updates a user")]
|
||||||
[Api(Description = "Updates a user")]
|
|
||||||
public class UpdateUser : UserDto, IReturnVoid
|
public class UpdateUser : UserDto, IReturnVoid
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -152,8 +144,7 @@ namespace MediaBrowser.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class CreateUser
|
/// Class CreateUser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Route("/Users", "POST")]
|
[Route("/Users", "POST", Summary = "Creates a user")]
|
||||||
[Api(Description = "Creates a user")]
|
|
||||||
public class CreateUser : UserDto, IReturn<UserDto>
|
public class CreateUser : UserDto, IReturn<UserDto>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System.Globalization;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net
|
namespace MediaBrowser.Common.Net
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,7 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <typeparam name="TStateType">The type of the T state type.</typeparam>
|
/// <typeparam name="TStateType">The type of the T state type.</typeparam>
|
||||||
public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable
|
public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable
|
||||||
where TStateType : class, new()
|
where TStateType : class, new()
|
||||||
|
where TReturnDataType : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _active connections
|
/// The _active connections
|
||||||
|
@ -144,12 +145,15 @@ namespace MediaBrowser.Common.Net
|
||||||
|
|
||||||
var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false);
|
var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false);
|
||||||
|
|
||||||
await connection.SendAsync(new WebSocketMessage<TReturnDataType>
|
if (data != null)
|
||||||
{
|
{
|
||||||
MessageType = Name,
|
await connection.SendAsync(new WebSocketMessage<TReturnDataType>
|
||||||
Data = data
|
{
|
||||||
|
MessageType = Name,
|
||||||
|
Data = data
|
||||||
|
|
||||||
}, tuple.Item2.Token).ConfigureAwait(false);
|
}, tuple.Item2.Token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
tuple.Item5.Release();
|
tuple.Item5.Release();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public class CodecProfile
|
public class CodecProfile
|
||||||
{
|
{
|
||||||
public CodecType Type { get; set; }
|
public CodecType Type { get; set; }
|
||||||
public List<ProfileCondition> Conditions { get; set; }
|
public ProfileCondition[] Conditions { get; set; }
|
||||||
public string Codec { get; set; }
|
public string Codec { get; set; }
|
||||||
|
|
||||||
public CodecProfile()
|
public CodecProfile()
|
||||||
{
|
{
|
||||||
Conditions = new List<ProfileCondition>();
|
Conditions = new ProfileCondition[] {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetCodecs()
|
public List<string> GetCodecs()
|
||||||
|
@ -32,6 +32,12 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public ProfileConditionType Condition { get; set; }
|
public ProfileConditionType Condition { get; set; }
|
||||||
public ProfileConditionValue Property { get; set; }
|
public ProfileConditionValue Property { get; set; }
|
||||||
public string Value { get; set; }
|
public string Value { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
|
||||||
|
public ProfileCondition()
|
||||||
|
{
|
||||||
|
IsRequired = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ProfileConditionType
|
public enum ProfileConditionType
|
||||||
|
@ -46,11 +52,17 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
{
|
{
|
||||||
AudioChannels,
|
AudioChannels,
|
||||||
AudioBitrate,
|
AudioBitrate,
|
||||||
|
AudioProfile,
|
||||||
Filesize,
|
Filesize,
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
|
Has64BitOffsets,
|
||||||
|
VideoBitDepth,
|
||||||
VideoBitrate,
|
VideoBitrate,
|
||||||
VideoFramerate,
|
VideoFramerate,
|
||||||
VideoLevel
|
VideoLevel,
|
||||||
|
VideoPacketLength,
|
||||||
|
VideoProfile,
|
||||||
|
VideoTimestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
MediaBrowser.Controller/Dlna/ContainerProfile.cs
Normal file
22
MediaBrowser.Controller/Dlna/ContainerProfile.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Dlna
|
namespace MediaBrowser.Controller.Dlna
|
||||||
{
|
{
|
||||||
public class DeviceIdentification
|
public class DeviceIdentification
|
||||||
|
@ -55,11 +54,11 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
/// Gets or sets the headers.
|
/// Gets or sets the headers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The headers.</value>
|
/// <value>The headers.</value>
|
||||||
public List<HttpHeaderInfo> Headers { get; set; }
|
public HttpHeaderInfo[] Headers { get; set; }
|
||||||
|
|
||||||
public DeviceIdentification()
|
public DeviceIdentification()
|
||||||
{
|
{
|
||||||
Headers = new List<HttpHeaderInfo>();
|
Headers = new HttpHeaderInfo[] {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +72,7 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public enum HeaderMatchType
|
public enum HeaderMatchType
|
||||||
{
|
{
|
||||||
Equals = 0,
|
Equals = 0,
|
||||||
Substring = 1
|
Regex = 1,
|
||||||
|
Substring = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,15 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The transcoding profiles.</value>
|
/// <value>The transcoding profiles.</value>
|
||||||
public TranscodingProfile[] TranscodingProfiles { get; set; }
|
public TranscodingProfile[] TranscodingProfiles { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the direct play profiles.
|
/// Gets or sets the direct play profiles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The direct play profiles.</value>
|
/// <value>The direct play profiles.</value>
|
||||||
public DirectPlayProfile[] DirectPlayProfiles { get; set; }
|
public DirectPlayProfile[] DirectPlayProfiles { get; set; }
|
||||||
|
|
||||||
|
public ContainerProfile[] ContainerProfiles { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the identification.
|
/// Gets or sets the identification.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -40,6 +42,9 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public string ModelDescription { get; set; }
|
public string ModelDescription { get; set; }
|
||||||
public string ModelNumber { get; set; }
|
public string ModelNumber { get; set; }
|
||||||
public string ModelUrl { get; set; }
|
public string ModelUrl { get; set; }
|
||||||
|
public bool IgnoreTranscodeByteRangeRequests { get; set; }
|
||||||
|
public bool SupportsAlbumArtInDidl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.
|
/// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -60,12 +65,16 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
|
|
||||||
public int TimelineOffsetSeconds { get; set; }
|
public int TimelineOffsetSeconds { get; set; }
|
||||||
|
|
||||||
|
public bool RequiresPlainVideoItems { get; set; }
|
||||||
|
public bool RequiresPlainFolders { get; set; }
|
||||||
|
|
||||||
public DeviceProfile()
|
public DeviceProfile()
|
||||||
{
|
{
|
||||||
DirectPlayProfiles = new DirectPlayProfile[] { };
|
DirectPlayProfiles = new DirectPlayProfile[] { };
|
||||||
TranscodingProfiles = new TranscodingProfile[] { };
|
TranscodingProfiles = new TranscodingProfile[] { };
|
||||||
MediaProfiles = new MediaProfile[] { };
|
MediaProfiles = new MediaProfile[] { };
|
||||||
CodecProfiles = new CodecProfile[] { };
|
CodecProfiles = new CodecProfile[] { };
|
||||||
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,15 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
{
|
{
|
||||||
public class DirectPlayProfile
|
public class DirectPlayProfile
|
||||||
{
|
{
|
||||||
public string[] Containers { get; set; }
|
public string Container { get; set; }
|
||||||
public string AudioCodec { get; set; }
|
public string AudioCodec { get; set; }
|
||||||
public string VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
|
|
||||||
public DlnaProfileType Type { get; set; }
|
public DlnaProfileType Type { get; set; }
|
||||||
|
|
||||||
public List<ProfileCondition> Conditions { get; set; }
|
public List<string> GetContainers()
|
||||||
|
|
||||||
public DirectPlayProfile()
|
|
||||||
{
|
{
|
||||||
Conditions = new List<ProfileCondition>();
|
return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||||
|
|
||||||
Containers = new string[] { };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetAudioCodecs()
|
public List<string> GetAudioCodecs()
|
||||||
|
|
|
@ -13,6 +13,13 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public string OrgPn { get; set; }
|
public string OrgPn { get; set; }
|
||||||
public string MimeType { get; set; }
|
public string MimeType { get; set; }
|
||||||
|
|
||||||
|
public ProfileCondition[] Conditions { get; set; }
|
||||||
|
|
||||||
|
public MediaProfile()
|
||||||
|
{
|
||||||
|
Conditions = new ProfileCondition[] {};
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> GetAudioCodecs()
|
public List<string> GetAudioCodecs()
|
||||||
{
|
{
|
||||||
return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Dlna
|
namespace MediaBrowser.Controller.Dlna
|
||||||
{
|
{
|
||||||
public class TranscodingProfile
|
public class TranscodingProfile
|
||||||
|
@ -11,12 +10,18 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
public string VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
public string AudioCodec { 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()
|
public TranscodingProfile()
|
||||||
{
|
{
|
||||||
Settings = new List<TranscodingSetting>();
|
Settings = new TranscodingSetting[] { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnableMpegtsM2TsMode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TranscodingSetting
|
public class TranscodingSetting
|
||||||
|
@ -27,6 +32,14 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
|
|
||||||
public enum TranscodingSettingType
|
public enum TranscodingSettingType
|
||||||
{
|
{
|
||||||
Profile
|
VideoLevel = 0,
|
||||||
|
VideoProfile = 1,
|
||||||
|
MaxAudioChannels = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TranscodeSeekInfo
|
||||||
|
{
|
||||||
|
Auto = 0,
|
||||||
|
Bytes = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
<Compile Include="Collections\CollectionCreationOptions.cs" />
|
||||||
<Compile Include="Collections\ICollectionManager.cs" />
|
<Compile Include="Collections\ICollectionManager.cs" />
|
||||||
<Compile Include="Dlna\CodecProfile.cs" />
|
<Compile Include="Dlna\CodecProfile.cs" />
|
||||||
|
<Compile Include="Dlna\ContainerProfile.cs" />
|
||||||
<Compile Include="Dlna\DeviceIdentification.cs" />
|
<Compile Include="Dlna\DeviceIdentification.cs" />
|
||||||
<Compile Include="Dlna\DirectPlayProfile.cs" />
|
<Compile Include="Dlna\DirectPlayProfile.cs" />
|
||||||
<Compile Include="Dlna\IDlnaManager.cs" />
|
<Compile Include="Dlna\IDlnaManager.cs" />
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using MediaBrowser.Dlna.Profiles;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -13,849 +14,42 @@ namespace MediaBrowser.Dlna
|
||||||
private IApplicationPaths _appPaths;
|
private IApplicationPaths _appPaths;
|
||||||
private readonly IXmlSerializer _xmlSerializer;
|
private readonly IXmlSerializer _xmlSerializer;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
||||||
public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem)
|
public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
|
||||||
{
|
{
|
||||||
_xmlSerializer = xmlSerializer;
|
_xmlSerializer = xmlSerializer;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
|
||||||
//GetProfiles();
|
GetProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<DeviceProfile> GetProfiles()
|
public IEnumerable<DeviceProfile> GetProfiles()
|
||||||
{
|
{
|
||||||
var list = new List<DeviceProfile>();
|
var list = new List<DeviceProfile>
|
||||||
|
|
||||||
list.Add(new DeviceProfile
|
|
||||||
{
|
{
|
||||||
Name = "Samsung TV (B Series)",
|
new SamsungSmartTvProfile(),
|
||||||
ClientType = "DLNA",
|
new Xbox360Profile(),
|
||||||
|
new XboxOneProfile(),
|
||||||
Identification = new DeviceIdentification
|
new SonyPs3Profile(),
|
||||||
{
|
new SonyBravia2010Profile(),
|
||||||
FriendlyName = "^TV$",
|
new SonyBravia2011Profile(),
|
||||||
ModelNumber = @"1\.0",
|
new SonyBravia2012Profile(),
|
||||||
ModelName = "Samsung DTV DMR"
|
new SonyBravia2013Profile(),
|
||||||
},
|
new SonyBlurayPlayer2013Profile(),
|
||||||
|
new SonyBlurayPlayerProfile(),
|
||||||
TranscodingProfiles = new[]
|
new PanasonicVieraProfile(),
|
||||||
{
|
new WdtvLiveProfile(),
|
||||||
new TranscodingProfile
|
new DenonAvrProfile(),
|
||||||
{
|
new LinksysDMA2100Profile(),
|
||||||
Container = "mp3",
|
new LgTvProfile()
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var item in list)
|
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;
|
return list;
|
||||||
|
@ -863,37 +57,7 @@ namespace MediaBrowser.Dlna
|
||||||
|
|
||||||
public DeviceProfile GetDefaultProfile()
|
public DeviceProfile GetDefaultProfile()
|
||||||
{
|
{
|
||||||
return new DeviceProfile
|
return new DefaultProfile();
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
|
public DeviceProfile GetProfile(DeviceIdentification deviceInfo)
|
||||||
|
@ -906,55 +70,55 @@ namespace MediaBrowser.Dlna
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.DeviceDescription))
|
if (!string.IsNullOrWhiteSpace(profileInfo.DeviceDescription))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
|
if (deviceInfo.DeviceDescription == null || !Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.FriendlyName))
|
if (!string.IsNullOrWhiteSpace(profileInfo.FriendlyName))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
|
if (deviceInfo.FriendlyName == null || !Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.Manufacturer))
|
if (!string.IsNullOrWhiteSpace(profileInfo.Manufacturer))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
|
if (deviceInfo.Manufacturer == null || !Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.ManufacturerUrl))
|
if (!string.IsNullOrWhiteSpace(profileInfo.ManufacturerUrl))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
|
if (deviceInfo.ManufacturerUrl == null || !Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.ModelDescription))
|
if (!string.IsNullOrWhiteSpace(profileInfo.ModelDescription))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
|
if (deviceInfo.ModelDescription == null || !Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.ModelName))
|
if (!string.IsNullOrWhiteSpace(profileInfo.ModelName))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName))
|
if (deviceInfo.ModelName == null || !Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.ModelNumber))
|
if (!string.IsNullOrWhiteSpace(profileInfo.ModelNumber))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
|
if (deviceInfo.ModelNumber == null || !Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.ModelUrl))
|
if (!string.IsNullOrWhiteSpace(profileInfo.ModelUrl))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
|
if (deviceInfo.ModelUrl == null || !Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profileInfo.SerialNumber))
|
if (!string.IsNullOrWhiteSpace(profileInfo.SerialNumber))
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
|
if (deviceInfo.SerialNumber == null || !Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,28 @@
|
||||||
<Compile Include="PlayTo\uIcon.cs" />
|
<Compile Include="PlayTo\uIcon.cs" />
|
||||||
<Compile Include="PlayTo\uParser.cs" />
|
<Compile Include="PlayTo\uParser.cs" />
|
||||||
<Compile Include="PlayTo\uPnpNamespaces.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="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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||||
|
@ -97,9 +118,7 @@
|
||||||
<Name>MediaBrowser.Model</Name>
|
<Name>MediaBrowser.Model</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Server\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|
|
@ -681,7 +681,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
|
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
|
||||||
if (presentationUrl != null)
|
if (presentationUrl != null)
|
||||||
deviceProperties.PresentationUrl = presentationUrl.Value;
|
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);
|
deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
public string ModelNumber { get; set; }
|
public string ModelNumber { get; set; }
|
||||||
|
|
||||||
|
public string ModelUrl { get; set; }
|
||||||
|
|
||||||
public string Manufacturer { get; set; }
|
public string Manufacturer { get; set; }
|
||||||
|
|
||||||
public string ManufacturerUrl { get; set; }
|
public string ManufacturerUrl { get; set; }
|
||||||
|
@ -72,7 +74,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
ModelName = ModelName,
|
ModelName = ModelName,
|
||||||
ModelNumber = ModelNumber,
|
ModelNumber = ModelNumber,
|
||||||
FriendlyName = Name,
|
FriendlyName = Name,
|
||||||
ManufacturerUrl = ManufacturerUrl
|
ManufacturerUrl = ManufacturerUrl,
|
||||||
|
ModelUrl = ModelUrl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
playlistItem.StartPositionTicks = newItem.StartPositionTicks;
|
playlistItem.StartPositionTicks = newItem.StartPositionTicks;
|
||||||
playlistItem.StreamUrl = newItem.StreamUrl;
|
playlistItem.StreamUrl = newItem.StreamUrl;
|
||||||
playlistItem.Didl = newItem.Didl;
|
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));
|
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)
|
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 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.StartPositionTicks = startPostionTicks;
|
||||||
|
playlistItem.DeviceProfileName = profile.Name;
|
||||||
|
|
||||||
if (playlistItem.MediaType == DlnaProfileType.Audio)
|
if (playlistItem.MediaType == DlnaProfileType.Audio)
|
||||||
{
|
{
|
||||||
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
|
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(deviceInfo, playlistItem, streams, serverAddress);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -410,32 +417,92 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
||||||
playlistItem.Didl = didl;
|
playlistItem.Didl = didl;
|
||||||
|
|
||||||
var header = StreamHelper.GetDlnaHeaders(playlistItem);
|
|
||||||
playlistItem.DlnaHeaders = header;
|
|
||||||
return playlistItem;
|
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;
|
var video = item as Video;
|
||||||
|
|
||||||
if (video != null)
|
if (video != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(video, profile);
|
return new PlaylistItemFactory().Create(video, mediaStreams, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var audio = item as Audio;
|
var audio = item as Audio;
|
||||||
|
|
||||||
if (audio != null)
|
if (audio != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(audio, profile);
|
return new PlaylistItemFactory().Create(audio, mediaStreams, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var photo = item as Photo;
|
var photo = item as Photo;
|
||||||
|
|
||||||
if (photo != null)
|
if (photo != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(photo, profile);
|
return new PlaylistItemFactory().Create(photo, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException("Unrecognized item type.");
|
throw new ArgumentException("Unrecognized item type.");
|
||||||
|
@ -482,11 +549,18 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
await _device.SetStop();
|
await _device.SetStop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTrack.PlayState = 1;
|
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)
|
if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
|
||||||
await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
|
await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +582,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
return Task.FromResult(false);
|
return Task.FromResult(false);
|
||||||
|
|
||||||
prevTrack.PlayState = 1;
|
prevTrack.PlayState = 1;
|
||||||
return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl);
|
return _device.SetAvTransport(prevTrack.StreamUrl, GetDlnaHeaders(prevTrack), prevTrack.Didl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Session;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -16,7 +17,6 @@ using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Session;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -54,10 +54,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
_logger.Log(LogSeverity.Info, "PlayTo-Manager starting");
|
|
||||||
|
|
||||||
_locations = new ConcurrentDictionary<string, DateTime>();
|
_locations = new ConcurrentDictionary<string, DateTime>();
|
||||||
|
|
||||||
foreach (var network in NetworkInterface.GetAllNetworkInterfaces())
|
foreach (var network in NetworkInterface.GetAllNetworkInterfaces())
|
||||||
|
@ -73,7 +71,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
IPAddress localIp = null;
|
IPAddress localIp = null;
|
||||||
|
|
||||||
foreach (UnicastIPAddressInformation ipInfo in network.GetIPProperties().UnicastAddresses)
|
foreach (var ipInfo in network.GetIPProperties().UnicastAddresses)
|
||||||
{
|
{
|
||||||
if (ipInfo.Address.AddressFamily == AddressFamily.InterNetwork)
|
if (ipInfo.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
|
@ -95,8 +93,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to Initilize Socket", e);
|
_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");
|
_logger.Info("SSDP listener - Task completed");
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException c)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -158,7 +154,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
await CreateController(uri).ConfigureAwait(false);
|
await CreateController(uri).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException c)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -180,10 +176,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900));
|
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)
|
catch (Exception ex)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -14,16 +15,29 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
public string Container { get; set; }
|
public string Container { get; set; }
|
||||||
|
|
||||||
public string MimeType { get; set; }
|
|
||||||
|
|
||||||
public int PlayState { get; set; }
|
public int PlayState { get; set; }
|
||||||
|
|
||||||
public string StreamUrl { get; set; }
|
public string StreamUrl { get; set; }
|
||||||
|
|
||||||
public string DlnaHeaders { get; set; }
|
|
||||||
|
|
||||||
public string Didl { get; set; }
|
public string Didl { get; set; }
|
||||||
|
|
||||||
public long StartPositionTicks { 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>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -12,15 +12,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
public class PlaylistItemFactory
|
public class PlaylistItemFactory
|
||||||
{
|
{
|
||||||
private readonly IItemRepository _itemRepo;
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
public PlaylistItemFactory(IItemRepository itemRepo)
|
public PlaylistItem Create(Audio item, List<MediaStream> mediaStreams, DeviceProfile profile)
|
||||||
{
|
|
||||||
_itemRepo = itemRepo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlaylistItem Create(Audio item, DeviceProfile profile)
|
|
||||||
{
|
{
|
||||||
var playlistItem = new PlaylistItem
|
var playlistItem = new PlaylistItem
|
||||||
{
|
{
|
||||||
|
@ -28,23 +22,21 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaType = DlnaProfileType.Audio
|
MediaType = DlnaProfileType.Audio
|
||||||
};
|
};
|
||||||
|
|
||||||
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id,
|
|
||||||
Type = MediaStreamType.Audio
|
|
||||||
});
|
|
||||||
|
|
||||||
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||||
|
|
||||||
var directPlay = profile.DirectPlayProfiles
|
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec)
|
||||||
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
|
.All(i => IsCodecProfileSupported(i, item.Path, null, audioStream)))
|
||||||
|
|
||||||
if (directPlay != null)
|
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = false;
|
var directPlay = profile.DirectPlayProfiles
|
||||||
playlistItem.Container = Path.GetExtension(item.Path);
|
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
|
||||||
|
|
||||||
return playlistItem;
|
if (directPlay != null)
|
||||||
|
{
|
||||||
|
playlistItem.Transcode = false;
|
||||||
|
playlistItem.Container = Path.GetExtension(item.Path);
|
||||||
|
|
||||||
|
return playlistItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var transcodingProfile = profile.TranscodingProfiles
|
var transcodingProfile = profile.TranscodingProfiles
|
||||||
|
@ -53,11 +45,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
|
playlistItem.AudioCodec = transcodingProfile.AudioCodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
@ -87,16 +78,14 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlaylistItem Create(Video item, DeviceProfile profile)
|
public PlaylistItem Create(Video item, List<MediaStream> mediaStreams, DeviceProfile profile)
|
||||||
{
|
{
|
||||||
var playlistItem = new PlaylistItem
|
var playlistItem = new PlaylistItem
|
||||||
{
|
{
|
||||||
|
@ -104,24 +93,22 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaType = DlnaProfileType.Video
|
MediaType = DlnaProfileType.Video
|
||||||
};
|
};
|
||||||
|
|
||||||
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id
|
|
||||||
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||||
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
||||||
|
|
||||||
var directPlay = profile.DirectPlayProfiles
|
if (profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec || i.Type == CodecType.VideoAudioCodec)
|
||||||
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
|
.All(i => IsCodecProfileSupported(i, item.Path, videoStream, audioStream)))
|
||||||
|
|
||||||
if (directPlay != null)
|
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = false;
|
var directPlay = profile.DirectPlayProfiles
|
||||||
playlistItem.Container = Path.GetExtension(item.Path);
|
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
|
||||||
|
|
||||||
return playlistItem;
|
if (directPlay != null)
|
||||||
|
{
|
||||||
|
playlistItem.Transcode = false;
|
||||||
|
playlistItem.Container = Path.GetExtension(item.Path);
|
||||||
|
|
||||||
|
return playlistItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var transcodingProfile = profile.TranscodingProfiles
|
var transcodingProfile = profile.TranscodingProfiles
|
||||||
|
@ -130,63 +117,29 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
|
playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault();
|
||||||
|
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
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)
|
private bool IsSupported(DirectPlayProfile profile, Photo item)
|
||||||
{
|
{
|
||||||
var mediaPath = item.Path;
|
var mediaPath = item.Path;
|
||||||
|
|
||||||
if (profile.Containers.Length > 0)
|
if (profile.Container.Length > 0)
|
||||||
{
|
{
|
||||||
// Check container type
|
// Check container type
|
||||||
var mediaContainer = Path.GetExtension(mediaPath);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check additional conditions
|
|
||||||
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, null)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,22 +147,16 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
var mediaPath = item.Path;
|
var mediaPath = item.Path;
|
||||||
|
|
||||||
if (profile.Containers.Length > 0)
|
if (profile.Container.Length > 0)
|
||||||
{
|
{
|
||||||
// Check container type
|
// Check container type
|
||||||
var mediaContainer = Path.GetExtension(mediaPath);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check additional conditions
|
|
||||||
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, audioStream)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,11 +169,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
var mediaPath = item.Path;
|
var mediaPath = item.Path;
|
||||||
|
|
||||||
if (profile.Containers.Length > 0)
|
if (profile.Container.Length > 0)
|
||||||
{
|
{
|
||||||
// Check container type
|
// Check container type
|
||||||
var mediaContainer = Path.GetExtension(mediaPath);
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +222,24 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
return true;
|
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>
|
/// <summary>
|
||||||
/// Determines whether [is condition satisfied] [the specified condition].
|
/// Determines whether [is condition satisfied] [the specified condition].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -292,30 +251,75 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
/// <exception cref="System.InvalidOperationException">Unexpected ProfileConditionType</exception>
|
/// <exception cref="System.InvalidOperationException">Unexpected ProfileConditionType</exception>
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
|
private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
|
||||||
{
|
{
|
||||||
var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream);
|
if (condition.Property == ProfileConditionValue.Has64BitOffsets)
|
||||||
|
|
||||||
if (actualValue.HasValue)
|
|
||||||
{
|
{
|
||||||
long expected;
|
// TODO: Determine how to evaluate this
|
||||||
if (long.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected))
|
}
|
||||||
|
|
||||||
|
if (condition.Property == ProfileConditionValue.VideoProfile)
|
||||||
|
{
|
||||||
|
var profile = videoStream == null ? null : videoStream.Profile;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(profile))
|
||||||
{
|
{
|
||||||
switch (condition.Condition)
|
switch (condition.Condition)
|
||||||
{
|
{
|
||||||
case ProfileConditionType.Equals:
|
case ProfileConditionType.Equals:
|
||||||
return actualValue.Value == expected;
|
return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
||||||
case ProfileConditionType.GreaterThanEqual:
|
|
||||||
return actualValue.Value >= expected;
|
|
||||||
case ProfileConditionType.LessThanEqual:
|
|
||||||
return actualValue.Value <= expected;
|
|
||||||
case ProfileConditionType.NotEquals:
|
case ProfileConditionType.NotEquals:
|
||||||
return actualValue.Value != expected;
|
return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
else if (condition.Property == ProfileConditionValue.AudioProfile)
|
||||||
|
{
|
||||||
|
var profile = audioStream == null ? null : audioStream.Profile;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(profile))
|
||||||
|
{
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream);
|
||||||
|
|
||||||
|
if (actualValue.HasValue)
|
||||||
|
{
|
||||||
|
long expected;
|
||||||
|
if (long.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected))
|
||||||
|
{
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return actualValue.Value == expected;
|
||||||
|
case ProfileConditionType.GreaterThanEqual:
|
||||||
|
return actualValue.Value >= expected;
|
||||||
|
case ProfileConditionType.LessThanEqual:
|
||||||
|
return actualValue.Value <= expected;
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return actualValue.Value != expected;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value doesn't exist in metadata. Fail it if required.
|
||||||
|
return !condition.IsRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -347,6 +351,12 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
return videoStream == null ? null : videoStream.Width;
|
return videoStream == null ? null : videoStream.Width;
|
||||||
case ProfileConditionValue.VideoLevel:
|
case ProfileConditionValue.VideoLevel:
|
||||||
return videoStream == null ? null : ConvertToLong(videoStream.Level);
|
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:
|
default:
|
||||||
throw new InvalidOperationException("Unexpected Property");
|
throw new InvalidOperationException("Unexpected Property");
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url.ToString(),
|
Url = url.ToString(),
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
|
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||||
};
|
};
|
||||||
|
|
||||||
options.RequestHeaders["HOST"] = ip + ":" + port;
|
options.RequestHeaders["HOST"] = ip + ":" + port;
|
||||||
|
@ -88,7 +88,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url.ToString(),
|
Url = url.ToString(),
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
|
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||||
};
|
};
|
||||||
|
|
||||||
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
|
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
|
||||||
|
@ -112,7 +112,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url.ToString(),
|
Url = url.ToString(),
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging
|
LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging
|
||||||
};
|
};
|
||||||
|
|
||||||
options.RequestHeaders["SOAPAction"] = soapAction;
|
options.RequestHeaders["SOAPAction"] = soapAction;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -9,91 +8,21 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
class StreamHelper
|
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>
|
/// <summary>
|
||||||
/// Gets the audio URL.
|
/// Gets the audio URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="deviceProperties">The device properties.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="streams">The streams.</param>
|
||||||
/// <param name="serverAddress">The server address.</param>
|
/// <param name="serverAddress">The server address.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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)
|
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{2}?Static=True", serverAddress, item.ItemId, item.Container);
|
|
||||||
|
|
||||||
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>
|
/// <summary>
|
||||||
/// Gets the video URL.
|
/// Gets the video URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -104,97 +33,41 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
/// <returns>The url to send to the device</returns>
|
/// <returns>The url to send to the device</returns>
|
||||||
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
|
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
|
||||||
{
|
{
|
||||||
string dlnaCommand = string.Empty;
|
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);
|
||||||
if (!item.Transcode)
|
|
||||||
{
|
|
||||||
dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, null, null, null, null, null, null, null, null, null, null, item.MimeType);
|
|
||||||
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);
|
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>
|
/// <summary>
|
||||||
/// Builds the dlna URL.
|
/// Builds the dlna URL.
|
||||||
/// </summary>
|
/// </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 usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
var dlnaparam = string.Format("Params={0};", deviceID);
|
var list = new List<string>
|
||||||
dlnaparam += isStatic ? "true;" : "false;";
|
{
|
||||||
dlnaparam += videoCodec.HasValue ? videoCodec.Value + ";" : ";";
|
deviceProfileName ?? string.Empty,
|
||||||
dlnaparam += audioCodec.HasValue ? audioCodec.Value + ";" : ";";
|
deviceID ?? string.Empty,
|
||||||
dlnaparam += audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) + ";" : ";";
|
mediaSourceId ?? string.Empty,
|
||||||
dlnaparam += subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) + ";" : ";";
|
isStatic.ToString().ToLower(),
|
||||||
dlnaparam += videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) + ";" : ";";
|
videoCodec ?? string.Empty,
|
||||||
dlnaparam += audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) + ";" : ";";
|
audioCodec ?? string.Empty,
|
||||||
dlnaparam += audiochannels.HasValue ? audiochannels.Value.ToString(usCulture) + ";" : ";";
|
audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) + ";" : ";";
|
subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += profile + ";";
|
videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += videoLevel + ";";
|
audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += mimeType + ";";
|
maxAudioChannels ?? string.Empty,
|
||||||
|
startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty,
|
||||||
|
profile ?? string.Empty,
|
||||||
|
videoLevel ?? string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
return dlnaparam;
|
return string.Format("Params={0}", string.Join(";", list.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
59
MediaBrowser.Dlna/Profiles/DefaultProfile.cs
Normal file
59
MediaBrowser.Dlna/Profiles/DefaultProfile.cs
Normal 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs
Normal file
27
MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs
Normal 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
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
192
MediaBrowser.Dlna/Profiles/LgTvProfile.cs
Normal file
192
MediaBrowser.Dlna/Profiles/LgTvProfile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs
Normal file
33
MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs
Normal 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
Normal file
186
MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
315
MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
Normal file
315
MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
Normal 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
180
MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
Normal file
180
MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
Normal file
File diff suppressed because one or more lines are too long
261
MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
Normal file
261
MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
Normal file
File diff suppressed because one or more lines are too long
286
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
Normal file
286
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
304
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
Normal file
304
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
246
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
Normal file
246
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
264
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
Normal file
264
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
233
MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs
Normal file
233
MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs
Normal 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
241
MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
Normal file
241
MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
312
MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
Normal file
312
MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
Normal file
54
MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
Normal 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
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs
Normal file
115
MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
164
MediaBrowser.Dlna/Server/Headers.cs
Normal file
164
MediaBrowser.Dlna/Server/Headers.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
MediaBrowser.Dlna/Server/RawHeaders.cs
Normal file
16
MediaBrowser.Dlna/Server/RawHeaders.cs
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
260
MediaBrowser.Dlna/Server/SsdpHandler.cs
Normal file
260
MediaBrowser.Dlna/Server/SsdpHandler.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
MediaBrowser.Dlna/Server/UpnpDevice.cs
Normal file
28
MediaBrowser.Dlna/Server/UpnpDevice.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1030,7 +1030,7 @@ namespace MediaBrowser.Model.ApiClient
|
||||||
/// <param name="timer">The timer.</param>
|
/// <param name="timer">The timer.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
Task CreateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken);
|
Task CreateLiveTvTimerAsync(BaseTimerInfoDto timer, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the live tv timer asynchronous.
|
/// Updates the live tv timer asynchronous.
|
||||||
|
|
|
@ -4,11 +4,15 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public class DlnaOptions
|
public class DlnaOptions
|
||||||
{
|
{
|
||||||
public bool EnablePlayTo { get; set; }
|
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()
|
public DlnaOptions()
|
||||||
{
|
{
|
||||||
EnablePlayTo = true;
|
EnablePlayTo = true;
|
||||||
|
EnableServer = true;
|
||||||
|
ClientDiscoveryIntervalSeconds = 60;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
/// Omit to copy
|
/// Omit to copy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The video codec.</value>
|
/// <value>The video codec.</value>
|
||||||
public VideoCodecs? VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the video bit rate.
|
/// Gets or sets the video bit rate.
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
/// Omit to copy the original stream
|
/// Omit to copy the original stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The audio encoding format.</value>
|
/// <value>The audio encoding format.</value>
|
||||||
public AudioCodecs? AudioCodec { get; set; }
|
public string AudioCodec { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the item id.
|
/// Gets or sets the item id.
|
||||||
|
@ -158,68 +158,4 @@
|
||||||
/// <value>The device id.</value>
|
/// <value>The device id.</value>
|
||||||
public string DeviceId { get; set; }
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,14 @@
|
||||||
using System;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
namespace MediaBrowser.Model.LiveTv
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("Name = {Name}")]
|
[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>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether [record any time].
|
/// Gets or sets a value indicating whether [record any time].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -105,36 +39,6 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// <value>The day pattern.</value>
|
/// <value>The day pattern.</value>
|
||||||
public DayPattern? DayPattern { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the image tags.
|
/// Gets or sets the image tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -156,7 +60,5 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
ImageTags = new Dictionary<ImageType, Guid>();
|
ImageTags = new Dictionary<ImageType, Guid>();
|
||||||
Days = new List<DayOfWeek>();
|
Days = new List<DayOfWeek>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,47 @@ using System.ComponentModel;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
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>
|
/// <summary>
|
||||||
/// Id of the recording.
|
/// Id of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -26,18 +65,12 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The external channel identifier.</value>
|
/// <value>The external channel identifier.</value>
|
||||||
public string ExternalChannelId { get; set; }
|
public string ExternalChannelId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ChannelName of the recording.
|
/// ChannelName of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ChannelName { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the program identifier.
|
/// Gets or sets the program identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -49,7 +82,7 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The external program identifier.</value>
|
/// <value>The external program identifier.</value>
|
||||||
public string ExternalProgramId { get; set; }
|
public string ExternalProgramId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the recording.
|
/// Name of the recording.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -71,22 +104,16 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
public DateTime EndDate { get; set; }
|
public DateTime EndDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the status.
|
/// Gets or sets the name of the service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The status.</value>
|
/// <value>The name of the service.</value>
|
||||||
public RecordingStatus Status { get; set; }
|
public string ServiceName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the series timer identifier.
|
/// Gets or sets the priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The series timer identifier.</value>
|
/// <value>The priority.</value>
|
||||||
public string SeriesTimerId { get; set; }
|
public int Priority { 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>
|
/// <summary>
|
||||||
/// Gets or sets the pre padding seconds.
|
/// Gets or sets the pre padding seconds.
|
||||||
|
@ -111,28 +138,5 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
|
||||||
public bool IsPostPaddingRequired { get; set; }
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||||
|
|
||||||
CreateRules(device);
|
CreateRules(device);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
//_logger.ErrorException("Error creating port forwarding rules", ex);
|
//_logger.ErrorException("Error creating port forwarding rules", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
{
|
{
|
||||||
MigrateUserFolders();
|
MigrateUserFolders();
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +498,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
|
var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
|
||||||
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
|
RegisterSingleInstance<IAppThemeManager>(appThemeManager);
|
||||||
|
|
||||||
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager);
|
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, JsonSerializer);
|
||||||
RegisterSingleInstance<IDlnaManager>(dlnaManager);
|
RegisterSingleInstance<IDlnaManager>(dlnaManager);
|
||||||
|
|
||||||
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
|
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
|
||||||
|
|
|
@ -3809,7 +3809,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
||||||
var deferred = $.Deferred();
|
var deferred = $.Deferred();
|
||||||
|
|
||||||
var msg = [itemId, canSeek, queueableMediaTypes];
|
var msg = [itemId, canSeek, queueableMediaTypes];
|
||||||
|
|
||||||
if (mediaSourceId) {
|
if (mediaSourceId) {
|
||||||
msg.push(mediaSourceId);
|
msg.push(mediaSourceId);
|
||||||
}
|
}
|
||||||
|
@ -4029,7 +4029,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
||||||
|
|
||||||
self.createPackageReview = function (review) {
|
self.createPackageReview = function (review) {
|
||||||
|
|
||||||
var url = self.getUrl("PackageReviews/" + review.id, review);
|
var url = self.getUrl("Packages/Reviews/" + review.id, review);
|
||||||
|
|
||||||
return self.ajax({
|
return self.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
@ -4058,7 +4058,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
||||||
options.ForceTitle = true;
|
options.ForceTitle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = self.getUrl("PackageReviews/" + packageId, options);
|
var url = self.getUrl("Packages/" + packageId + "Reviews", options);
|
||||||
|
|
||||||
return self.ajax({
|
return self.ajax({
|
||||||
type: "GET",
|
type: "GET",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.247" targetFramework="net45" />
|
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.248" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.343</version>
|
<version>3.0.345</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<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>
|
<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>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<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="NLog" version="2.1.0" />
|
||||||
<dependency id="SimpleInjector" version="2.4.1" />
|
<dependency id="SimpleInjector" version="2.4.1" />
|
||||||
<dependency id="sharpcompress" version="0.10.2" />
|
<dependency id="sharpcompress" version="0.10.2" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.343</version>
|
<version>3.0.345</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.343</version>
|
<version>3.0.345</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.343" />
|
<dependency id="MediaBrowser.Common" version="3.0.345" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user