diff options
95 files changed, 2321 insertions, 646 deletions
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs index 54141b3e2..4d8eed7dd 100644 --- a/MediaBrowser.Api/AppThemeService.cs +++ b/MediaBrowser.Api/AppThemeService.cs @@ -9,16 +9,14 @@ using System.Linq; namespace MediaBrowser.Api { - [Route("/Themes", "GET")] - [Api(Description = "Gets a list of available themes for an app")] + [Route("/Themes", "GET", Summary = "Gets a list of available themes for an app")] public class GetAppThemes : IReturn<List<AppThemeInfo>> { [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] public string App { get; set; } } - [Route("/Themes/Info", "GET")] - [Api(Description = "Gets an app theme")] + [Route("/Themes/Info", "GET", Summary = "Gets an app theme")] public class GetAppTheme : IReturn<AppTheme> { [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -28,8 +26,7 @@ namespace MediaBrowser.Api public string Name { get; set; } } - [Route("/Themes/Images", "GET")] - [Api(Description = "Gets an app theme")] + [Route("/Themes/Images", "GET", Summary = "Gets an app theme")] public class GetAppThemeImage { [ApiMember(Name = "App", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -45,12 +42,11 @@ namespace MediaBrowser.Api public string CacheTag { get; set; } } - [Route("/Themes", "POST")] - [Api(Description = "Saves a theme")] + [Route("/Themes", "POST", Summary = "Saves a theme")] public class SaveTheme : AppTheme, IReturnVoid { } - + public class AppThemeService : BaseApiService { private readonly IAppThemeManager _themeManager; diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 08686b43a..707cfb457 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; using ServiceStack.Web; using System; @@ -79,6 +80,20 @@ namespace MediaBrowser.Api } /// <summary> + /// Gets the session. + /// </summary> + /// <param name="sessionManager">The session manager.</param> + /// <returns>SessionInfo.</returns> + protected SessionInfo GetSession(ISessionManager sessionManager) + { + var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request); + + return sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) && + string.Equals(i.Client, auth.Client) && + string.Equals(i.ApplicationVersion, auth.Version)); + } + + /// <summary> /// To the cached result. /// </summary> /// <typeparam name="T"></typeparam> diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs index c1724571a..ed203a0f4 100644 --- a/MediaBrowser.Api/ChannelService.cs +++ b/MediaBrowser.Api/ChannelService.cs @@ -7,8 +7,7 @@ using System.Threading; namespace MediaBrowser.Api { - [Route("/Channels", "GET")] - [Api(("Gets available channels"))] + [Route("/Channels", "GET", Summary = "Gets available channels")] public class GetChannels : IReturn<QueryResult<BaseItemDto>> { public string UserId { get; set; } @@ -18,8 +17,7 @@ namespace MediaBrowser.Api public int? Limit { get; set; } } - [Route("/Channels/{Id}/Items", "GET")] - [Api(("Gets channel items"))] + [Route("/Channels/{Id}/Items", "GET", Summary = "Gets channel items")] public class GetChannelItems : IReturn<QueryResult<BaseItemDto>> { public string Id { get; set; } diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 600704350..b3191cd4b 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetConfiguration /// </summary> - [Route("/System/Configuration", "GET")] - [Api(("Gets application configuration"))] + [Route("/System/Configuration", "GET", Summary = "Gets application configuration")] public class GetConfiguration : IReturn<ServerConfiguration> { @@ -27,28 +26,24 @@ namespace MediaBrowser.Api /// <summary> /// Class UpdateConfiguration /// </summary> - [Route("/System/Configuration", "POST")] - [Api(("Updates application configuration"))] + [Route("/System/Configuration", "POST", Summary = "Updates application configuration")] public class UpdateConfiguration : ServerConfiguration, IReturnVoid { } - [Route("/System/Configuration/MetadataOptions/Default", "GET")] - [Api(("Gets a default MetadataOptions object"))] + [Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")] public class GetDefaultMetadataOptions : IReturn<MetadataOptions> { } - [Route("/System/Configuration/MetadataPlugins", "GET")] - [Api(("Gets all available metadata plugins"))] + [Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")] public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>> { } - [Route("/System/Configuration/VideoImageExtraction", "POST")] - [Api(("Updates image extraction for all types"))] + [Route("/System/Configuration/VideoImageExtraction", "POST", Summary = "Updates image extraction for all types")] public class UpdateVideoImageExtraction : IReturnVoid { public bool Enabled { get; set; } diff --git a/MediaBrowser.Api/DlnaService.cs b/MediaBrowser.Api/DlnaService.cs new file mode 100644 index 000000000..792a7ff43 --- /dev/null +++ b/MediaBrowser.Api/DlnaService.cs @@ -0,0 +1,90 @@ +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Model.Dlna; +using ServiceStack; +using System.Collections.Generic; +using System.Linq; + +namespace MediaBrowser.Api +{ + [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")] + public class GetProfileInfos : IReturn<List<DeviceProfileInfo>> + { + } + + [Route("/Dlna/Profiles/{Id}", "DELETE", Summary = "Deletes a profile")] + public class DeleteProfile : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] + public string Id { get; set; } + } + + [Route("/Dlna/Profiles/Default", "GET", Summary = "Gets the default profile")] + public class GetDefaultProfile : IReturn<DeviceProfile> + { + } + + [Route("/Dlna/Profiles/{Id}", "GET", Summary = "Gets a single profile")] + public class GetProfile : IReturn<DeviceProfile> + { + [ApiMember(Name = "Id", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + [Route("/Dlna/Profiles/{ProfileId}", "POST", Summary = "Updates a profile")] + public class UpdateProfile : DeviceProfile, IReturnVoid + { + [ApiMember(Name = "ProfileId", Description = "Profile Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string ProfileId { get; set; } + } + + [Route("/Dlna/Profiles", "POST", Summary = "Creates a profile")] + public class CreateProfile : DeviceProfile, IReturnVoid + { + } + + public class DlnaService : BaseApiService + { + private readonly IDlnaManager _dlnaManager; + + public DlnaService(IDlnaManager dlnaManager) + { + _dlnaManager = dlnaManager; + } + + public object Get(GetProfileInfos request) + { + var result = _dlnaManager.GetProfileInfos().ToList(); + + return ToOptimizedResult(result); + } + + public object Get(GetProfile request) + { + var result = _dlnaManager.GetProfile(request.Id); + + return ToOptimizedResult(result); + } + + public object Get(GetDefaultProfile request) + { + var result = _dlnaManager.GetDefaultProfile(); + + return ToOptimizedResult(result); + } + + public void Delete(DeleteProfile request) + { + _dlnaManager.DeleteProfile(request.Id); + } + + public void Post(UpdateProfile request) + { + _dlnaManager.UpdateProfile(request); + } + + public void Post(CreateProfile request) + { + _dlnaManager.CreateProfile(request); + } + } +} diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 2cdaef1ed..562da40ee 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -15,7 +15,6 @@ using ServiceStack.Text.Controller; using ServiceStack.Web; using System; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Linq; using System.Threading; @@ -776,15 +775,6 @@ namespace MediaBrowser.Api.Images var bytes = Convert.FromBase64String(text); - // Validate first - using (var validationStream = new MemoryStream(bytes)) - { - // This will throw an exception if it's not a valid image - using (Image.FromStream(validationStream)) - { - } - } - var memoryStream = new MemoryStream(bytes) { Position = 0 diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index dba256418..533a92fba 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Session; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -245,12 +246,13 @@ namespace MediaBrowser.Api.Library private readonly IDtoService _dtoService; private readonly IChannelManager _channelManager; + private readonly ISessionManager _sessionManager; /// <summary> /// Initializes a new instance of the <see cref="LibraryService" /> class. /// </summary> public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, - IDtoService dtoService, IUserDataManager userDataManager, IChannelManager channelManager) + IDtoService dtoService, IUserDataManager userDataManager, IChannelManager channelManager, ISessionManager sessionManager) { _itemRepo = itemRepo; _libraryManager = libraryManager; @@ -258,6 +260,7 @@ namespace MediaBrowser.Api.Library _dtoService = dtoService; _userDataManager = userDataManager; _channelManager = channelManager; + _sessionManager = sessionManager; } public object Get(GetMediaFolders request) @@ -504,6 +507,13 @@ namespace MediaBrowser.Api.Library { var item = _dtoService.GetItemByDtoId(request.Id); + var session = GetSession(_sessionManager); + + if (!session.UserId.HasValue || !_userManager.GetUserById(session.UserId.Value).Configuration.EnableContentDeletion) + { + throw new UnauthorizedAccessException("This operation requires a logged in user with delete access."); + } + return _libraryManager.DeleteItem(item); } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 569e4b52b..96fe01ab3 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -12,14 +12,12 @@ using System.Threading.Tasks; namespace MediaBrowser.Api.LiveTv { - [Route("/LiveTv/Info", "GET")] - [Api(Description = "Gets available live tv services.")] + [Route("/LiveTv/Info", "GET", Summary = "Gets available live tv services.")] public class GetLiveTvInfo : IReturn<LiveTvInfo> { } - [Route("/LiveTv/Channels", "GET")] - [Api(Description = "Gets available live tv channels.")] + [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")] public class GetChannels : IReturn<QueryResult<ChannelInfoDto>> { [ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -43,8 +41,7 @@ namespace MediaBrowser.Api.LiveTv public int? Limit { get; set; } } - [Route("/LiveTv/Channels/{Id}", "GET")] - [Api(Description = "Gets a live tv channel")] + [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")] public class GetChannel : IReturn<ChannelInfoDto> { /// <summary> @@ -58,8 +55,7 @@ namespace MediaBrowser.Api.LiveTv public string UserId { get; set; } } - [Route("/LiveTv/Recordings", "GET")] - [Api(Description = "Gets live tv recordings")] + [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")] public class GetRecordings : IReturn<QueryResult<RecordingInfoDto>> { [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -87,16 +83,14 @@ namespace MediaBrowser.Api.LiveTv public string SeriesTimerId { get; set; } } - [Route("/LiveTv/Recordings/Groups", "GET")] - [Api(Description = "Gets live tv recording groups")] + [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")] public class GetRecordingGroups : IReturn<QueryResult<RecordingGroupDto>> { [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string UserId { get; set; } } - [Route("/LiveTv/Recordings/{Id}", "GET")] - [Api(Description = "Gets a live tv recording")] + [Route("/LiveTv/Recordings/{Id}", "GET", Summary = "Gets a live tv recording")] public class GetRecording : IReturn<RecordingInfoDto> { [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -106,32 +100,28 @@ namespace MediaBrowser.Api.LiveTv public string UserId { get; set; } } - [Route("/LiveTv/Tuners/{Id}/Reset", "POST")] - [Api(Description = "Resets a tv tuner")] + [Route("/LiveTv/Tuners/{Id}/Reset", "POST", Summary = "Resets a tv tuner")] public class ResetTuner : IReturnVoid { [ApiMember(Name = "Id", Description = "Tuner Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/Timers/{Id}", "GET")] - [Api(Description = "Gets a live tv timer")] + [Route("/LiveTv/Timers/{Id}", "GET", Summary = "Gets a live tv timer")] public class GetTimer : IReturn<TimerInfoDto> { [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/Timers/Defaults", "GET")] - [Api(Description = "Gets default values for a new timer")] + [Route("/LiveTv/Timers/Defaults", "GET", Summary = "Gets default values for a new timer")] public class GetDefaultTimer : IReturn<SeriesTimerInfoDto> { [ApiMember(Name = "ProgramId", Description = "Optional, to attach default values based on a program.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string ProgramId { get; set; } } - [Route("/LiveTv/Timers", "GET")] - [Api(Description = "Gets live tv timers")] + [Route("/LiveTv/Timers", "GET", Summary = "Gets live tv timers")] public class GetTimers : IReturn<QueryResult<TimerInfoDto>> { [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -141,8 +131,7 @@ namespace MediaBrowser.Api.LiveTv public string SeriesTimerId { get; set; } } - [Route("/LiveTv/Programs", "GET,POST")] - [Api(Description = "Gets available live tv epgs..")] + [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] public class GetPrograms : IReturn<QueryResult<ProgramInfoDto>> { [ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] @@ -164,8 +153,7 @@ namespace MediaBrowser.Api.LiveTv public string MaxEndDate { get; set; } } - [Route("/LiveTv/Programs/Recommended", "GET")] - [Api(Description = "Gets available live tv epgs..")] + [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] public class GetRecommendedPrograms : IReturn<QueryResult<ProgramInfoDto>> { [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] @@ -181,8 +169,7 @@ namespace MediaBrowser.Api.LiveTv public bool? HasAired { get; set; } } - [Route("/LiveTv/Programs/{Id}", "GET")] - [Api(Description = "Gets a live tv program")] + [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")] public class GetProgram : IReturn<ProgramInfoDto> { [ApiMember(Name = "Id", Description = "Program Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -193,44 +180,38 @@ namespace MediaBrowser.Api.LiveTv } - [Route("/LiveTv/Recordings/{Id}", "DELETE")] - [Api(Description = "Deletes a live tv recording")] + [Route("/LiveTv/Recordings/{Id}", "DELETE", Summary = "Deletes a live tv recording")] public class DeleteRecording : IReturnVoid { [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/Timers/{Id}", "DELETE")] - [Api(Description = "Cancels a live tv timer")] + [Route("/LiveTv/Timers/{Id}", "DELETE", Summary = "Cancels a live tv timer")] public class CancelTimer : IReturnVoid { [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/Timers/{Id}", "POST")] - [Api(Description = "Updates a live tv timer")] + [Route("/LiveTv/Timers/{Id}", "POST", Summary = "Updates a live tv timer")] public class UpdateTimer : TimerInfoDto, IReturnVoid { } - [Route("/LiveTv/Timers", "POST")] - [Api(Description = "Creates a live tv timer")] + [Route("/LiveTv/Timers", "POST", Summary = "Creates a live tv timer")] public class CreateTimer : TimerInfoDto, IReturnVoid { } - [Route("/LiveTv/SeriesTimers/{Id}", "GET")] - [Api(Description = "Gets a live tv series timer")] + [Route("/LiveTv/SeriesTimers/{Id}", "GET", Summary = "Gets a live tv series timer")] public class GetSeriesTimer : IReturn<TimerInfoDto> { [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/SeriesTimers", "GET")] - [Api(Description = "Gets live tv series timers")] + [Route("/LiveTv/SeriesTimers", "GET", Summary = "Gets live tv series timers")] public class GetSeriesTimers : IReturn<QueryResult<SeriesTimerInfoDto>> { [ApiMember(Name = "SortBy", Description = "Optional. Sort by SortName or Priority", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] @@ -240,36 +221,31 @@ namespace MediaBrowser.Api.LiveTv public SortOrder SortOrder { get; set; } } - [Route("/LiveTv/SeriesTimers/{Id}", "DELETE")] - [Api(Description = "Cancels a live tv series timer")] + [Route("/LiveTv/SeriesTimers/{Id}", "DELETE", Summary = "Cancels a live tv series timer")] public class CancelSeriesTimer : IReturnVoid { [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/SeriesTimers/{Id}", "POST")] - [Api(Description = "Updates a live tv series timer")] + [Route("/LiveTv/SeriesTimers/{Id}", "POST", Summary = "Updates a live tv series timer")] public class UpdateSeriesTimer : SeriesTimerInfoDto, IReturnVoid { } - [Route("/LiveTv/SeriesTimers", "POST")] - [Api(Description = "Creates a live tv series timer")] + [Route("/LiveTv/SeriesTimers", "POST", Summary = "Creates a live tv series timer")] public class CreateSeriesTimer : SeriesTimerInfoDto, IReturnVoid { } - [Route("/LiveTv/Recordings/Groups/{Id}", "GET")] - [Api(Description = "Gets a recording group")] + [Route("/LiveTv/Recordings/Groups/{Id}", "GET", Summary = "Gets a recording group")] public class GetRecordingGroup : IReturn<RecordingGroupDto> { [ApiMember(Name = "Id", Description = "Recording group Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } - [Route("/LiveTv/GuideInfo", "GET")] - [Api(Description = "Gets guide info")] + [Route("/LiveTv/GuideInfo", "GET", Summary = "Gets guide info")] public class GetGuideInfo : IReturn<GuideInfo> { } diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 38cf39b54..18559a68d 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -53,7 +53,6 @@ <Reference Include="System.Core" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> - <Reference Include="System.Drawing" /> <Reference Include="System.Xml" /> <Reference Include="ServiceStack.Interfaces"> <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath> @@ -67,6 +66,7 @@ <Link>Properties\SharedVersion.cs</Link> </Compile> <Compile Include="ChannelService.cs" /> + <Compile Include="DlnaService.cs" /> <Compile Include="Movies\CollectionService.cs" /> <Compile Include="Music\AlbumsService.cs" /> <Compile Include="AppThemeService.cs" /> diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 204a7aab4..228dc378b 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api.Movies /// <summary> /// Class GetSimilarMovies /// </summary> - [Route("/Movies/{Id}/Similar", "GET")] - [Api(Description = "Finds movies and trailers similar to a given movie.")] + [Route("/Movies/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given movie.")] public class GetSimilarMovies : BaseGetSimilarItemsFromItem { [ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] @@ -30,8 +29,7 @@ namespace MediaBrowser.Api.Movies } } - [Route("/Movies/Recommendations", "GET")] - [Api(Description = "Gets movie recommendations")] + [Route("/Movies/Recommendations", "GET", Summary = "Gets movie recommendations")] public class GetMovieRecommendations : IReturn<RecommendationDto[]>, IHasItemFields { [ApiMember(Name = "CategoryLimit", Description = "The max number of categories to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs index 057506635..05e6a9577 100644 --- a/MediaBrowser.Api/Movies/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -10,8 +10,7 @@ namespace MediaBrowser.Api.Movies /// <summary> /// Class GetSimilarTrailers /// </summary> - [Route("/Trailers/{Id}/Similar", "GET")] - [Api(Description = "Finds movies and trailers similar to a given trailer.")] + [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] public class GetSimilarTrailers : BaseGetSimilarItemsFromItem { } diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index a8446a7ef..9b9df3a92 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -9,28 +9,24 @@ using System.Linq; namespace MediaBrowser.Api.Music { - [Route("/Songs/{Id}/InstantMix", "GET")] - [Api(Description = "Creates an instant playlist based on a given song")] + [Route("/Songs/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given song")] public class GetInstantMixFromSong : BaseGetSimilarItemsFromItem { } - [Route("/Albums/{Id}/InstantMix", "GET")] - [Api(Description = "Creates an instant playlist based on a given album")] + [Route("/Albums/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given album")] public class GetInstantMixFromAlbum : BaseGetSimilarItemsFromItem { } - [Route("/Artists/{Name}/InstantMix", "GET")] - [Api(Description = "Creates an instant playlist based on a given artist")] + [Route("/Artists/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given artist")] public class GetInstantMixFromArtist : BaseGetSimilarItems { [ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Name { get; set; } } - [Route("/MusicGenres/{Name}/InstantMix", "GET")] - [Api(Description = "Creates an instant playlist based on a music genre")] + [Route("/MusicGenres/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a music genre")] public class GetInstantMixFromMusicGenre : BaseGetSimilarItems { [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f65949ac7..2002e594c 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1210,85 +1210,89 @@ namespace MediaBrowser.Api.Playback if (i == 0) { - request.DeviceId = val; + request.DeviceProfileId = val; } else if (i == 1) { - request.MediaSourceId = val; + request.DeviceId = val; } else if (i == 2) { - request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + request.MediaSourceId = val; } else if (i == 3) { + request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + else if (i == 4) + { if (videoRequest != null) { videoRequest.VideoCodec = val; } } - else if (i == 4) + else if (i == 5) { request.AudioCodec = val; } - else if (i == 5) + else if (i == 6) { if (videoRequest != null) { videoRequest.AudioStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 6) + else if (i == 7) { if (videoRequest != null) { videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 7) + else if (i == 8) { if (videoRequest != null) { videoRequest.VideoBitRate = int.Parse(val, UsCulture); } } - else if (i == 8) + else if (i == 9) { request.AudioBitRate = int.Parse(val, UsCulture); } - else if (i == 9) + else if (i == 10) { request.MaxAudioChannels = int.Parse(val, UsCulture); } - else if (i == 10) + else if (i == 11) { if (videoRequest != null) { videoRequest.MaxWidth = int.Parse(val, UsCulture); } } - else if (i == 11) + else if (i == 12) { if (videoRequest != null) { videoRequest.MaxHeight = int.Parse(val, UsCulture); } } - else if (i == 12) + else if (i == 13) { if (videoRequest != null) { videoRequest.Framerate = int.Parse(val, UsCulture); } } - else if (i == 13) + else if (i == 14) { if (videoRequest != null) { request.StartTimeTicks = long.Parse(val, UsCulture); } } - else if (i == 14) + else if (i == 15) { if (videoRequest != null) { @@ -1488,7 +1492,16 @@ namespace MediaBrowser.Api.Playback headers[key] = Request.Headers[key]; } - var profile = DlnaManager.GetProfile(headers); + var profile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ? + DlnaManager.GetProfile(headers) : + DlnaManager.GetProfile(state.Request.DeviceProfileId); + + if (profile == null) + { + // Don't use settings from the default profile. + // Only use a specific profile if it was requested. + return; + } var container = Path.GetExtension(state.RequestedUrl); diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index dad8a51bd..78b3f2948 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -26,7 +26,8 @@ namespace MediaBrowser.Api.Playback.Progressive protected readonly IImageProcessor ImageProcessor; protected readonly IHttpClient HttpClient; - protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) + protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) + : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { HttpClient = httpClient; ImageProcessor = imageProcessor; @@ -216,18 +217,30 @@ namespace MediaBrowser.Api.Playback.Progressive var contentType = state.GetMimeType(outputPath); + var contentLength = state.EstimateContentLength ? GetEstimatedContentLength(state) : null; + + if (contentLength.HasValue) + { + responseHeaders["Content-Length"] = contentLength.Value.ToString(UsCulture); + } + // Headers only if (isHeadRequest) { var streamResult = ResultFactory.GetResult(new byte[] { }, contentType, responseHeaders); - var hasOptions = streamResult as IHasOptions; - if (hasOptions != null) + + if (!contentLength.HasValue) { - if (hasOptions.Options.ContainsKey("Content-Length")) + var hasOptions = streamResult as IHasOptions; + if (hasOptions != null) { - hasOptions.Options.Remove("Content-Length"); + if (hasOptions.Options.ContainsKey("Content-Length")) + { + hasOptions.Options.Remove("Content-Length"); + } } } + return streamResult; } @@ -252,5 +265,26 @@ namespace MediaBrowser.Api.Playback.Progressive return result; } + + private long? GetEstimatedContentLength(StreamState state) + { + var totalBitrate = 0; + + if (state.Request.AudioBitRate.HasValue) + { + totalBitrate += state.Request.AudioBitRate.Value; + } + if (state.VideoRequest != null && state.VideoRequest.VideoBitRate.HasValue) + { + totalBitrate += state.VideoRequest.VideoBitRate.Value; + } + + if (totalBitrate > 0 && state.RunTimeTicks.HasValue) + { + return Convert.ToInt64(totalBitrate * TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds); + } + + return null; + } } } diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 0fc78f0e3..855c03691 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -138,6 +138,11 @@ namespace MediaBrowser.Api.Playback.Progressive return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf h264_mp4toannexb" : args; } + if (state.EnableMpegtsM2TsMode) + { + args += " -mpegts_m2ts_mode 1"; + } + const string keyFrameArg = " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))"; args += keyFrameArg; diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 8db5920f6..0eb2984fb 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -65,6 +65,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "Static", Description = "Optional. If true, the original file will be streamed statically without any encoding. Use either no url extension or the original file extension. true/false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool Static { get; set; } + [ApiMember(Name = "DeviceProfileId", Description = "Optional. The dlna device profile id to utilize.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string DeviceProfileId { get; set; } + /// <summary> /// For testing purposes /// </summary> diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index daa735fe5..80080fbb3 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -2,18 +2,17 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Model.Tasks; using ServiceStack; +using ServiceStack.Text.Controller; using System; using System.Collections.Generic; using System.Linq; -using ServiceStack.Text.Controller; namespace MediaBrowser.Api.ScheduledTasks { /// <summary> /// Class GetScheduledTask /// </summary> - [Route("/ScheduledTasks/{Id}", "GET")] - [Api(Description = "Gets a scheduled task, by Id")] + [Route("/ScheduledTasks/{Id}", "GET", Summary = "Gets a scheduled task, by Id")] public class GetScheduledTask : IReturn<TaskInfo> { /// <summary> @@ -27,8 +26,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// <summary> /// Class GetScheduledTasks /// </summary> - [Route("/ScheduledTasks", "GET")] - [Api(Description = "Gets scheduled tasks")] + [Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")] public class GetScheduledTasks : IReturn<List<TaskInfo>> { [ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] @@ -38,8 +36,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// <summary> /// Class StartScheduledTask /// </summary> - [Route("/ScheduledTasks/Running/{Id}", "POST")] - [Api(Description = "Starts a scheduled task")] + [Route("/ScheduledTasks/Running/{Id}", "POST", Summary = "Starts a scheduled task")] public class StartScheduledTask : IReturnVoid { /// <summary> @@ -53,8 +50,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// <summary> /// Class StopScheduledTask /// </summary> - [Route("/ScheduledTasks/Running/{Id}", "DELETE")] - [Api(Description = "Stops a scheduled task")] + [Route("/ScheduledTasks/Running/{Id}", "DELETE", Summary = "Stops a scheduled task")] public class StopScheduledTask : IReturnVoid { /// <summary> @@ -68,8 +64,7 @@ namespace MediaBrowser.Api.ScheduledTasks /// <summary> /// Class UpdateScheduledTaskTriggers /// </summary> - [Route("/ScheduledTasks/{Id}/Triggers", "POST")] - [Api(Description = "Updates the triggers for a scheduled task")] + [Route("/ScheduledTasks/{Id}/Triggers", "POST", Summary = "Updates the triggers for a scheduled task")] public class UpdateScheduledTaskTriggers : List<TaskTriggerInfo>, IReturnVoid { /// <summary> diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs index fc7fdd160..7eff5054b 100644 --- a/MediaBrowser.Api/UserLibrary/StudiosService.cs +++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs @@ -8,15 +8,13 @@ using ServiceStack; using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace MediaBrowser.Api.UserLibrary { /// <summary> /// Class GetStudios /// </summary> - [Route("/Studios", "GET")] - [Api(Description = "Gets all studios from a given item, folder, or the entire library")] + [Route("/Studios", "GET", Summary = "Gets all studios from a given item, folder, or the entire library")] public class GetStudios : GetItemsByName { } @@ -24,8 +22,7 @@ namespace MediaBrowser.Api.UserLibrary /// <summary> /// Class GetStudio /// </summary> - [Route("/Studios/{Name}", "GET")] - [Api(Description = "Gets a studio, by name")] + [Route("/Studios/{Name}", "GET", Summary = "Gets a studio, by name")] public class GetStudio : IReturn<BaseItemDto> { /// <summary> diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index c6051c02c..a49f957f6 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -705,7 +705,7 @@ namespace MediaBrowser.Api.UserLibrary datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); } - var session = GetSession(); + var session = GetSession(_sessionManager); var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false); @@ -719,15 +719,6 @@ namespace MediaBrowser.Api.UserLibrary return dto; } - private SessionInfo GetSession() - { - var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request); - - return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) && - string.Equals(i.Client, auth.Client) && - string.Equals(i.ApplicationVersion, auth.Version)); - } - /// <summary> /// Posts the specified request. /// </summary> @@ -744,7 +735,7 @@ namespace MediaBrowser.Api.UserLibrary { CanSeek = request.CanSeek, Item = item, - SessionId = GetSession().Id, + SessionId = GetSession(_sessionManager).Id, QueueableMediaTypes = queueableMediaTypes.Split(',').ToList(), MediaSourceId = request.MediaSourceId }; @@ -768,7 +759,7 @@ namespace MediaBrowser.Api.UserLibrary PositionTicks = request.PositionTicks, IsMuted = request.IsMuted, IsPaused = request.IsPaused, - SessionId = GetSession().Id, + SessionId = GetSession(_sessionManager).Id, MediaSourceId = request.MediaSourceId }; @@ -787,7 +778,7 @@ namespace MediaBrowser.Api.UserLibrary var item = _dtoService.GetItemByDtoId(request.Id, user.Id); - var session = GetSession(); + var session = GetSession(_sessionManager); var info = new PlaybackStopInfo { @@ -817,7 +808,7 @@ namespace MediaBrowser.Api.UserLibrary { var user = _userManager.GetUserById(request.UserId); - var session = GetSession(); + var session = GetSession(_sessionManager); var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false); diff --git a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs index 38139645e..25acd613c 100644 --- a/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Api.WebSocket /// <returns>Task{SystemInfo}.</returns> protected override Task<IEnumerable<SessionInfoDto>> GetDataToSend(object state) { - return Task.FromResult(_sessionManager.Sessions.Select(_dtoService.GetSessionInfoDto)); + return Task.FromResult(_sessionManager.Sessions.Where(i => i.IsActive).Select(_dtoService.GetSessionInfoDto)); } } } diff --git a/MediaBrowser.Controller/Dlna/CodecProfile.cs b/MediaBrowser.Controller/Dlna/CodecProfile.cs index 2b9a40ea0..75f80ed3b 100644 --- a/MediaBrowser.Controller/Dlna/CodecProfile.cs +++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs @@ -1,13 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class CodecProfile { + [XmlAttribute("type")] public CodecType Type { get; set; } + public ProfileCondition[] Conditions { get; set; } + + [XmlAttribute("codec")] public string Codec { get; set; } public CodecProfile() @@ -37,9 +42,16 @@ namespace MediaBrowser.Controller.Dlna public class ProfileCondition { + [XmlAttribute("condition")] public ProfileConditionType Condition { get; set; } + + [XmlAttribute("property")] public ProfileConditionValue Property { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } + + [XmlAttribute("isRequired")] public bool IsRequired { get; set; } public ProfileCondition() @@ -69,8 +81,6 @@ namespace MediaBrowser.Controller.Dlna VideoBitrate, VideoFramerate, VideoLevel, - VideoPacketLength, - VideoProfile, - VideoTimestamp + VideoProfile } } diff --git a/MediaBrowser.Controller/Dlna/ContainerProfile.cs b/MediaBrowser.Controller/Dlna/ContainerProfile.cs index 3bd3c9eaf..1029ba72c 100644 --- a/MediaBrowser.Controller/Dlna/ContainerProfile.cs +++ b/MediaBrowser.Controller/Dlna/ContainerProfile.cs @@ -1,12 +1,16 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class ContainerProfile { + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } public ProfileCondition[] Conditions { get; set; } + + [XmlAttribute("container")] public string Container { get; set; } public ContainerProfile() diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs index 7b8e3a1e7..c9cd4bc70 100644 --- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs @@ -1,4 +1,6 @@ +using System.Xml.Serialization; + namespace MediaBrowser.Controller.Dlna { public class DeviceIdentification @@ -62,8 +64,13 @@ namespace MediaBrowser.Controller.Dlna public class HttpHeaderInfo { + [XmlAttribute("name")] public string Name { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } + + [XmlAttribute("match")] public HeaderMatchType Match { get; set; } } diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index f34c4bf64..5950698fb 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -1,9 +1,14 @@ -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { + [XmlRoot("Profile")] public class DeviceProfile { /// <summary> @@ -12,19 +17,11 @@ namespace MediaBrowser.Controller.Dlna /// <value>The name.</value> public string Name { get; set; } - /// <summary> - /// Gets or sets the transcoding profiles. - /// </summary> - /// <value>The transcoding profiles.</value> - public TranscodingProfile[] TranscodingProfiles { get; set; } + [XmlIgnore] + public string Id { get; set; } - /// <summary> - /// Gets or sets the direct play profiles. - /// </summary> - /// <value>The direct play profiles.</value> - public DirectPlayProfile[] DirectPlayProfiles { get; set; } - - public ContainerProfile[] ContainerProfiles { get; set; } + [XmlIgnore] + public DeviceProfileType ProfileType { get; set; } /// <summary> /// Gets or sets the identification. @@ -40,7 +37,9 @@ namespace MediaBrowser.Controller.Dlna public string ModelNumber { get; set; } public string ModelUrl { get; set; } public bool IgnoreTranscodeByteRangeRequests { get; set; } - public bool SupportsAlbumArtInDidl { get; set; } + public bool EnableAlbumArtInDidl { get; set; } + + public string SupportedMediaTypes { get; set; } /// <summary> /// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace. @@ -57,14 +56,27 @@ namespace MediaBrowser.Controller.Dlna public string ProtocolInfo { get; set; } - public MediaProfile[] MediaProfiles { get; set; } - public CodecProfile[] CodecProfiles { get; set; } - public int TimelineOffsetSeconds { get; set; } - public bool RequiresPlainVideoItems { get; set; } public bool RequiresPlainFolders { get; set; } + /// <summary> + /// Gets or sets the direct play profiles. + /// </summary> + /// <value>The direct play profiles.</value> + public DirectPlayProfile[] DirectPlayProfiles { get; set; } + + /// <summary> + /// Gets or sets the transcoding profiles. + /// </summary> + /// <value>The transcoding profiles.</value> + public TranscodingProfile[] TranscodingProfiles { get; set; } + + public ContainerProfile[] ContainerProfiles { get; set; } + + public CodecProfile[] CodecProfiles { get; set; } + public MediaProfile[] MediaProfiles { get; set; } + public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; @@ -72,6 +84,13 @@ namespace MediaBrowser.Controller.Dlna MediaProfiles = new MediaProfile[] { }; CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; + + SupportedMediaTypes = "Audio,Photo,Video"; + } + + public List<string> GetSupportedMediaTypes() + { + return (SupportedMediaTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); } public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec) diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs index 686b31287..ad70640da 100644 --- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs @@ -1,14 +1,21 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class DirectPlayProfile { + [XmlAttribute("container")] public string Container { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } public List<string> GetContainers() diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 22d13fc3a..521d17e01 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,28 +1,54 @@ -using System.Collections.Generic; +using MediaBrowser.Model.Dlna; +using System.Collections.Generic; namespace MediaBrowser.Controller.Dlna { public interface IDlnaManager { /// <summary> - /// Gets the dlna profiles. + /// Gets the profile infos. /// </summary> - /// <returns>IEnumerable{DlnaProfile}.</returns> - IEnumerable<DeviceProfile> GetProfiles(); + /// <returns>IEnumerable{DeviceProfileInfo}.</returns> + IEnumerable<DeviceProfileInfo> GetProfileInfos(); + + /// <summary> + /// Gets the profile. + /// </summary> + /// <param name="headers">The headers.</param> + /// <returns>DeviceProfile.</returns> + DeviceProfile GetProfile(IDictionary<string,string> headers); /// <summary> /// Gets the default profile. /// </summary> - /// <returns>DlnaProfile.</returns> + /// <returns>DeviceProfile.</returns> DeviceProfile GetDefaultProfile(); /// <summary> + /// Creates the profile. + /// </summary> + /// <param name="profile">The profile.</param> + void CreateProfile(DeviceProfile profile); + + /// <summary> + /// Updates the profile. + /// </summary> + /// <param name="profile">The profile.</param> + void UpdateProfile(DeviceProfile profile); + + /// <summary> + /// Deletes the profile. + /// </summary> + /// <param name="id">The identifier.</param> + void DeleteProfile(string id); + + /// <summary> /// Gets the profile. /// </summary> - /// <param name="headers">The headers.</param> + /// <param name="id">The identifier.</param> /// <returns>DeviceProfile.</returns> - DeviceProfile GetProfile(IDictionary<string,string> headers); - + DeviceProfile GetProfile(string id); + /// <summary> /// Gets the profile. /// </summary> diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs index 9a9b56ddd..bf3057294 100644 --- a/MediaBrowser.Controller/Dlna/MediaProfile.cs +++ b/MediaBrowser.Controller/Dlna/MediaProfile.cs @@ -1,16 +1,27 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class MediaProfile { + [XmlAttribute("container")] public string Container { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } + + [XmlAttribute("orgPn")] public string OrgPn { get; set; } + + [XmlAttribute("mimeType")] public string MimeType { get; set; } public ProfileCondition[] Conditions { get; set; } diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs index d4cfae989..289333aa7 100644 --- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs @@ -1,19 +1,30 @@ using System.Collections.Generic; using System.Linq; +using System.Xml.Serialization; namespace MediaBrowser.Controller.Dlna { public class TranscodingProfile { + [XmlAttribute("container")] public string Container { get; set; } + [XmlAttribute("type")] public DlnaProfileType Type { get; set; } + [XmlAttribute("videoCodec")] public string VideoCodec { get; set; } + + [XmlAttribute("audioCodec")] public string AudioCodec { get; set; } + [XmlAttribute("estimateContentLength")] public bool EstimateContentLength { get; set; } + + [XmlAttribute("enableMpegtsM2TsMode")] public bool EnableMpegtsM2TsMode { get; set; } + + [XmlAttribute("transcodeSeekInfo")] public TranscodeSeekInfo TranscodeSeekInfo { get; set; } public TranscodingSetting[] Settings { get; set; } @@ -32,7 +43,10 @@ namespace MediaBrowser.Controller.Dlna public class TranscodingSetting { + [XmlAttribute("name")] public TranscodingSettingType Name { get; set; } + + [XmlAttribute("value")] public string Value { get; set; } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index b3d73dc34..53ec030a7 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -3,8 +3,9 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; -using System.Runtime.Serialization; +using System.Globalization; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -22,7 +23,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The preferred metadata country code.</value> public string PreferredMetadataCountryCode { get; set; } - + public Trailer() { RemoteTrailers = new List<MediaUrl>(); @@ -33,19 +34,19 @@ namespace MediaBrowser.Controller.Entities } public float? Metascore { get; set; } - + public List<Guid> LocalTrailerIds { get; set; } - + public List<MediaUrl> RemoteTrailers { get; set; } public List<string> Keywords { get; set; } - + /// <summary> /// Gets or sets the taglines. /// </summary> /// <value>The taglines.</value> public List<string> Taglines { get; set; } - + /// <summary> /// Gets or sets the budget. /// </summary> @@ -92,6 +93,12 @@ namespace MediaBrowser.Controller.Entities { key = key + "-trailer"; + // Make sure different trailers have their own data. + if (RunTimeTicks.HasValue) + { + key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture); + } + return key; } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index e6a62c181..0a34b8016 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -121,10 +121,7 @@ namespace MediaBrowser.Controller.Entities { _configuration = value; - if (value == null) - { - _configurationInitialized = false; - } + _configurationInitialized = value != null; } } diff --git a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs b/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs index e113521ec..39d1c3220 100644 --- a/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs +++ b/MediaBrowser.Controller/MediaEncoding/InternalMediaInfoResult.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Entities; -using System.Collections.Generic; +using System.Collections.Generic; namespace MediaBrowser.Controller.MediaEncoding { @@ -24,7 +23,18 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets or sets the chapters. /// </summary> /// <value>The chapters.</value> - public List<ChapterInfo> Chapters { get; set; } + public MediaChapter[] Chapters { get; set; } + } + + public class MediaChapter + { + public int id { get; set; } + public string time_base { get; set; } + public long start { get; set; } + public string start_time { get; set; } + public long end { get; set; } + public string end_time { get; set; } + public Dictionary<string, string> tags { get; set; } } /// <summary> diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 184033177..fd1f65101 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -154,7 +154,8 @@ namespace MediaBrowser.Controller.MediaEncoding Codec = streamInfo.codec_name, Profile = streamInfo.profile, Level = streamInfo.level, - Index = streamInfo.index + Index = streamInfo.index, + PixelFormat = streamInfo.pix_fmt }; if (streamInfo.tags != null) @@ -196,24 +197,21 @@ namespace MediaBrowser.Controller.MediaEncoding } // Get stream bitrate - if (stream.Type != MediaStreamType.Subtitle) - { - var bitrate = 0; + var bitrate = 0; - if (!string.IsNullOrEmpty(streamInfo.bit_rate)) - { - bitrate = int.Parse(streamInfo.bit_rate, UsCulture); - } - else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate)) - { - // If the stream info doesn't have a bitrate get the value from the media format info - bitrate = int.Parse(formatInfo.bit_rate, UsCulture); - } + if (!string.IsNullOrEmpty(streamInfo.bit_rate)) + { + bitrate = int.Parse(streamInfo.bit_rate, UsCulture); + } + else if (formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video) + { + // If the stream info doesn't have a bitrate get the value from the media format info + bitrate = int.Parse(formatInfo.bit_rate, UsCulture); + } - if (bitrate > 0) - { - stream.BitRate = bitrate; - } + if (bitrate > 0) + { + stream.BitRate = bitrate; } if (streamInfo.disposition != null) diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 78876d239..edccc71c9 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,10 +1,14 @@ using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; using MediaBrowser.Dlna.Profiles; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -12,22 +16,37 @@ namespace MediaBrowser.Dlna { public class DlnaManager : IDlnaManager { - private IApplicationPaths _appPaths; + private readonly IApplicationPaths _appPaths; private readonly IXmlSerializer _xmlSerializer; private readonly IFileSystem _fileSystem; - private readonly IJsonSerializer _jsonSerializer; + private readonly ILogger _logger; - public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer) + public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IApplicationPaths appPaths, ILogger logger) { _xmlSerializer = xmlSerializer; _fileSystem = fileSystem; - _jsonSerializer = jsonSerializer; + _appPaths = appPaths; + _logger = logger; - GetProfiles(); + //DumpProfiles(); } public IEnumerable<DeviceProfile> GetProfiles() { + ExtractProfilesIfNeeded(); + + var list = GetProfiles(UserProfilesPath, DeviceProfileType.User) + .OrderBy(i => i.Name) + .ToList(); + + list.AddRange(GetProfiles(SystemProfilesPath, DeviceProfileType.System) + .OrderBy(i => i.Name)); + + return list; + } + + private void DumpProfiles() + { var list = new List<DeviceProfile> { new SamsungSmartTvProfile(), @@ -45,27 +64,71 @@ namespace MediaBrowser.Dlna new DenonAvrProfile(), new LinksysDMA2100Profile(), new LgTvProfile(), - new Foobar2000Profile() + new Foobar2000Profile(), + new DefaultProfile() }; foreach (var item in list) { - //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml"); - //_jsonSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".json"); + var path = Path.Combine(_appPaths.ProgramDataPath, _fileSystem.GetValidFilename(item.Name) + ".xml"); + + _xmlSerializer.SerializeToFile(item, path); } + } - return list; + private bool _extracted; + private readonly object _syncLock = new object(); + private void ExtractProfilesIfNeeded() + { + if (!_extracted) + { + lock (_syncLock) + { + if (!_extracted) + { + try + { + ExtractSystemProfiles(); + } + catch (Exception ex) + { + _logger.ErrorException("Error extracting DLNA profiles.", ex); + } + + _extracted = true; + } + + } + } } public DeviceProfile GetDefaultProfile() { + ExtractProfilesIfNeeded(); + return new DefaultProfile(); } public DeviceProfile GetProfile(DeviceIdentification deviceInfo) { - return GetProfiles().FirstOrDefault(i => IsMatch(deviceInfo, i.Identification)) ?? - GetDefaultProfile(); + if (deviceInfo == null) + { + throw new ArgumentNullException("deviceInfo"); + } + + var profile = GetProfiles() + .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification)); + + if (profile != null) + { + _logger.Debug("Found matching device profile: {0}", profile.Name); + } + else + { + _logger.Debug("No matching device profile found. The default will need to be used."); + } + + return profile; } private bool IsMatch(DeviceIdentification deviceInfo, DeviceIdentification profileInfo) @@ -129,8 +192,12 @@ namespace MediaBrowser.Dlna public DeviceProfile GetProfile(IDictionary<string, string> headers) { - return GetProfiles().FirstOrDefault(i => IsMatch(headers, i.Identification)) ?? - GetDefaultProfile(); + if (headers == null) + { + throw new ArgumentNullException("headers"); + } + + return GetProfiles().FirstOrDefault(i => IsMatch(headers, i.Identification)); } private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo) @@ -159,5 +226,171 @@ namespace MediaBrowser.Dlna return false; } + + private string UserProfilesPath + { + get + { + return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "user"); + } + } + + private string SystemProfilesPath + { + get + { + return Path.Combine(_appPaths.ConfigurationDirectoryPath, "dlna", "system"); + } + } + + private IEnumerable<DeviceProfile> GetProfiles(string path, DeviceProfileType type) + { + try + { + return new DirectoryInfo(path) + .EnumerateFiles("*", SearchOption.TopDirectoryOnly) + .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) + .Select(i => ParseProfileXmlFile(i.FullName, type)) + .Where(i => i != null) + .ToList(); + } + catch (DirectoryNotFoundException) + { + return new List<DeviceProfile>(); + } + } + + private DeviceProfile ParseProfileXmlFile(string path, DeviceProfileType type) + { + try + { + var profile = (DeviceProfile)_xmlSerializer.DeserializeFromFile(typeof(DeviceProfile), path); + + profile.Id = path.ToLower().GetMD5().ToString("N"); + profile.ProfileType = type; + + return profile; + } + catch (Exception ex) + { + _logger.ErrorException("Error parsing profile xml: {0}", ex, path); + + return null; + } + } + + public DeviceProfile GetProfile(string id) + { + if (string.IsNullOrWhiteSpace(id)) + { + throw new ArgumentNullException("id"); + } + + var info = GetProfileInfosInternal().First(i => string.Equals(i.Info.Id, id)); + + return ParseProfileXmlFile(info.Path, info.Info.Type); + } + + private IEnumerable<InternalProfileInfo> GetProfileInfosInternal() + { + ExtractProfilesIfNeeded(); + + return GetProfileInfos(UserProfilesPath, DeviceProfileType.User) + .Concat(GetProfileInfos(SystemProfilesPath, DeviceProfileType.System)) + .OrderBy(i => i.Info.Type == DeviceProfileType.User ? 0 : 1) + .ThenBy(i => i.Info.Name); + } + + public IEnumerable<DeviceProfileInfo> GetProfileInfos() + { + return GetProfileInfosInternal().Select(i => i.Info); + } + + private IEnumerable<InternalProfileInfo> GetProfileInfos(string path, DeviceProfileType type) + { + try + { + return new DirectoryInfo(path) + .EnumerateFiles("*", SearchOption.TopDirectoryOnly) + .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) + .Select(i => new InternalProfileInfo + { + Path = i.FullName, + + Info = new DeviceProfileInfo + { + Id = i.FullName.ToLower().GetMD5().ToString("N"), + Name = Path.GetFileNameWithoutExtension(i.FullName), + Type = type + } + }) + .ToList(); + } + catch (DirectoryNotFoundException) + { + return new List<InternalProfileInfo>(); + } + } + + private void ExtractSystemProfiles() + { + var assembly = GetType().Assembly; + var namespaceName = GetType().Namespace + ".Profiles.Xml."; + + var systemProfilesPath = SystemProfilesPath; + + foreach (var name in assembly.GetManifestResourceNames() + .Where(i => i.StartsWith(namespaceName)) + .ToList()) + { + var filename = Path.GetFileName(name).Substring(namespaceName.Length); + + var path = Path.Combine(systemProfilesPath, filename); + + using (var stream = assembly.GetManifestResourceStream(name)) + { + var fileInfo = new FileInfo(path); + + if (!fileInfo.Exists || fileInfo.Length != stream.Length) + { + Directory.CreateDirectory(systemProfilesPath); + + using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + stream.CopyTo(fileStream); + } + } + } + } + + // Not necessary, but just to make it easy to find + Directory.CreateDirectory(UserProfilesPath); + } + + public void DeleteProfile(string id) + { + var info = GetProfileInfosInternal().First(i => string.Equals(id, i.Info.Id)); + + if (info.Info.Type == DeviceProfileType.System) + { + throw new ArgumentException("System profiles cannot be deleted."); + } + + File.Delete(info.Path); + } + + public void CreateProfile(DeviceProfile profile) + { + } + + public void UpdateProfile(DeviceProfile profile) + { + } + + class InternalProfileInfo + { + internal DeviceProfileInfo Info { get; set; } + internal string Path { get; set; } + } } }
\ No newline at end of file diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index bdfcae39b..df1fed12f 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -117,7 +117,27 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> - <ItemGroup /> + <ItemGroup> + <EmbeddedResource Include="Profiles\Xml\Denon AVR.xml" /> + <EmbeddedResource Include="Profiles\Xml\foobar2000.xml" /> + <EmbeddedResource Include="Profiles\Xml\LG Smart TV.xml" /> + <EmbeddedResource Include="Profiles\Xml\Linksys DMA2100.xml" /> + <EmbeddedResource Include="Profiles\Xml\Panasonic Viera.xml" /> + <EmbeddedResource Include="Profiles\Xml\Samsung Smart TV.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Blu-ray Player 2013.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Blu-ray Player.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282010%29.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282011%29.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282012%29.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony Bravia %282013%29.xml" /> + <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 3.xml" /> + <EmbeddedResource Include="Profiles\Xml\WDTV Live.xml" /> + <EmbeddedResource Include="Profiles\Xml\Xbox 360.xml" /> + <EmbeddedResource Include="Profiles\Xml\Xbox One.xml" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Profiles\Xml\Default.xml" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs b/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs index 24158b890..c34293e52 100644 --- a/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs +++ b/MediaBrowser.Dlna/PlayTo/CurrentIdEventArgs.cs @@ -4,18 +4,6 @@ namespace MediaBrowser.Dlna.PlayTo { public class CurrentIdEventArgs : EventArgs { - public Guid Id { get; set; } - - public CurrentIdEventArgs(string id) - { - if (string.IsNullOrWhiteSpace(id) || id == "0") - { - Id = Guid.Empty; - } - else - { - Id = new Guid(id); - } - } + public string Id { get; set; } } } diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index a677cf5dd..fa0bfbca8 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Dlna.PlayTo if (_currentId == value) return; _currentId = value; + NotifyCurrentIdChanged(value); } } @@ -250,7 +251,7 @@ namespace MediaBrowser.Dlna.PlayTo StopTimer(); await SetStop().ConfigureAwait(false); - CurrentId = "0"; + CurrentId = null; var command = AvCommands.ServiceActions.FirstOrDefault(c => c.Name == "SetAVTransportURI"); if (command == null) @@ -514,7 +515,7 @@ namespace MediaBrowser.Dlna.PlayTo if (String.IsNullOrEmpty(track)) { - CurrentId = "0"; + CurrentId = null; return; } @@ -775,7 +776,7 @@ namespace MediaBrowser.Dlna.PlayTo private void NotifyCurrentIdChanged(string value) { if (CurrentIdChanged != null) - CurrentIdChanged.Invoke(this, new CurrentIdEventArgs(value)); + CurrentIdChanged.Invoke(this, new CurrentIdEventArgs { Id = value }); } #endregion diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index 0b0c03fcd..e4bd8819d 100644 --- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs +++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Dlna.PlayTo public class PlayToController : ISessionController, IDisposable { private Device _device; - private BaseItem _currentItem = null; + private BaseItem _currentItem; private readonly SessionInfo _session; private readonly ISessionManager _sessionManager; private readonly IItemRepository _itemRepository; @@ -30,7 +30,7 @@ namespace MediaBrowser.Dlna.PlayTo private readonly IDlnaManager _dlnaManager; private readonly IUserManager _userManager; private readonly IServerApplicationHost _appHost; - private bool _playbackStarted = false; + private bool _playbackStarted; private const int UpdateTimerIntervalMs = 1000; @@ -103,22 +103,27 @@ namespace MediaBrowser.Dlna.PlayTo async void Device_CurrentIdChanged(object sender, CurrentIdEventArgs e) { - if (e.Id != Guid.Empty) + if (!string.IsNullOrWhiteSpace(e.Id)) { - if (_currentItem != null && _currentItem.Id == e.Id) + Guid guid; + + if (Guid.TryParse(e.Id, out guid)) { - return; - } + if (_currentItem != null && _currentItem.Id == guid) + { + return; + } - var item = _libraryManager.GetItemById(e.Id); + var item = _libraryManager.GetItemById(guid); - if (item != null) - { - _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id); - _currentItem = item; - _playbackStarted = false; + if (item != null) + { + _logger.Debug("{0} - CurrentId {1}", _session.DeviceName, item.Id); + _currentItem = item; + _playbackStarted = false; - await ReportProgress().ConfigureAwait(false); + await ReportProgress().ConfigureAwait(false); + } } } } @@ -167,8 +172,8 @@ namespace MediaBrowser.Dlna.PlayTo { Item = _currentItem, SessionId = _session.Id, - CanSeek = true, - QueueableMediaTypes = new List<string> { "Audio", "Video" } + CanSeek = true, + QueueableMediaTypes = new List<string> { _currentItem.MediaType } }).ConfigureAwait(false); @@ -414,10 +419,12 @@ namespace MediaBrowser.Dlna.PlayTo var deviceInfo = _device.Properties; - var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()); + var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ?? + _dlnaManager.GetDefaultProfile(); var playlistItem = GetPlaylistItem(item, streams, profile); playlistItem.StartPositionTicks = startPostionTicks; + playlistItem.DeviceProfileId = profile.Id; if (playlistItem.MediaType == DlnaProfileType.Audio) { diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index 297f7a696..9e73450cb 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -239,9 +239,13 @@ namespace MediaBrowser.Dlna.PlayTo controller.Init(device); + var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ?? + _dlnaManager.GetDefaultProfile(); + _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities { - PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo }, + PlayableMediaTypes = profile.GetSupportedMediaTypes().ToArray(), + SupportsFullscreenToggle = false }); diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs index e1eea0824..50605c61f 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs @@ -46,6 +46,8 @@ namespace MediaBrowser.Dlna.PlayTo public int? MaxFramerate { get; set; } + public string DeviceProfileId { get; set; } + public PlaylistItem() { TranscodingSettings = new List<TranscodingSetting>(); diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs index 0dec9bbf3..f79dc1e5f 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs @@ -191,9 +191,7 @@ namespace MediaBrowser.Dlna.PlayTo case ProfileConditionValue.AudioProfile: case ProfileConditionValue.Has64BitOffsets: case ProfileConditionValue.VideoBitDepth: - case ProfileConditionValue.VideoPacketLength: case ProfileConditionValue.VideoProfile: - case ProfileConditionValue.VideoTimestamp: { // Not supported yet break; @@ -461,12 +459,6 @@ namespace MediaBrowser.Dlna.PlayTo return videoStream == null ? null : videoStream.Width; case ProfileConditionValue.VideoLevel: return videoStream == null ? null : ConvertToLong(videoStream.Level); - case ProfileConditionValue.VideoPacketLength: - // TODO: Determine how to get this - return null; - case ProfileConditionValue.VideoTimestamp: - // TODO: Determine how to get this - return null; default: throw new InvalidOperationException("Unexpected Property"); } diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs index b1ae21a43..42c788d38 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs +++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs @@ -22,7 +22,11 @@ namespace MediaBrowser.Dlna.PlayTo _config = config; } - public async Task<XDocument> SendCommandAsync(string baseUrl, DeviceService service, string command, string postData, string header = null) + public async Task<XDocument> SendCommandAsync(string baseUrl, + DeviceService service, + string command, + string postData, + string header = null) { var serviceUrl = service.ControlUrl; if (!serviceUrl.StartsWith("/")) @@ -40,7 +44,12 @@ namespace MediaBrowser.Dlna.PlayTo } } - public async Task SubscribeAsync(string url, string ip, int port, string localIp, int eventport, int timeOut = 3600) + public async Task SubscribeAsync(string url, + string ip, + int port, + string localIp, + int eventport, + int timeOut = 3600) { var options = new HttpRequestOptions { @@ -59,7 +68,11 @@ namespace MediaBrowser.Dlna.PlayTo } } - public async Task RespondAsync(Uri url, string ip, int port, string localIp, int eventport, int timeOut = 20000) + public async Task RespondAsync(Uri url, + string ip, + int port, + string localIp, + int eventport) { var options = new HttpRequestOptions { @@ -97,7 +110,10 @@ namespace MediaBrowser.Dlna.PlayTo } } - private Task<HttpResponseInfo> PostSoapDataAsync(string url, string soapAction, string postData, string header = null) + private Task<HttpResponseInfo> PostSoapDataAsync(string url, + string soapAction, + string postData, + string header = null) { if (!soapAction.StartsWith("\"")) soapAction = "\"" + soapAction + "\""; diff --git a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs index a4855c94f..b65e94fd1 100644 --- a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs +++ b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs @@ -1,8 +1,6 @@ -using MediaBrowser.Controller.Dlna; -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Globalization; -using System.Linq; namespace MediaBrowser.Dlna.PlayTo { @@ -47,6 +45,7 @@ namespace MediaBrowser.Dlna.PlayTo var list = new List<string> { + item.DeviceProfileId ?? string.Empty, deviceProperties.UUID ?? string.Empty, item.MediaSourceId ?? string.Empty, (!item.Transcode).ToString().ToLower(), diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs index 214b6f814..0efe18755 100644 --- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class DefaultProfile : DeviceProfile { public DefaultProfile() @@ -10,6 +12,7 @@ namespace MediaBrowser.Dlna.Profiles ProtocolInfo = "DLNA"; + FriendlyName = "Media Browser"; Manufacturer = "Media Browser"; ModelDescription = "Media Browser"; ModelName = "Media Browser"; diff --git a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs index cca6ab6bb..3c5064ad6 100644 --- a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class DenonAvrProfile : DefaultProfile { public DenonAvrProfile() diff --git a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs index 877f1a666..198b0a73a 100644 --- a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs @@ -1,13 +1,17 @@ using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class Foobar2000Profile : DefaultProfile { public Foobar2000Profile() { Name = "foobar2000"; + SupportedMediaTypes = "Audio"; + Identification = new DeviceIdentification { FriendlyName = @"foobar", diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs index ec20c9df8..7ca8069da 100644 --- a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class LgTvProfile : DefaultProfile { public LgTvProfile() diff --git a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs index e7086c205..a64cd24f3 100644 --- a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs +++ b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class LinksysDMA2100Profile : DefaultProfile { public LinksysDMA2100Profile() diff --git a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs index 6755c0680..64747776c 100644 --- a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs +++ b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs @@ -1,19 +1,21 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { - public class PanasonicVieraProfile : DefaultProfile + [XmlRoot("Profile")] + public class PanasonicVieraProfile : DefaultProfile { - public PanasonicVieraProfile() - { - Name = "Panasonic Viera"; + public PanasonicVieraProfile() + { + Name = "Panasonic Viera"; - Identification = new DeviceIdentification - { - FriendlyName = @"VIERA", - Manufacturer = "Panasonic", + Identification = new DeviceIdentification + { + FriendlyName = @"VIERA", + Manufacturer = "Panasonic", - Headers = new[] + Headers = new[] { new HttpHeaderInfo { @@ -22,11 +24,11 @@ namespace MediaBrowser.Dlna.Profiles Match = HeaderMatchType.Substring } } - }; + }; - TimelineOffsetSeconds = 10; + TimelineOffsetSeconds = 10; - TranscodingProfiles = new[] + TranscodingProfiles = new[] { new TranscodingProfile { @@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Profiles } }; - DirectPlayProfiles = new[] + DirectPlayProfiles = new[] { new DirectPlayProfile { @@ -127,7 +129,7 @@ namespace MediaBrowser.Dlna.Profiles } }; - ContainerProfiles = new[] + ContainerProfiles = new[] { new ContainerProfile { @@ -151,7 +153,7 @@ namespace MediaBrowser.Dlna.Profiles } }; - CodecProfiles = new[] + CodecProfiles = new[] { new CodecProfile { @@ -181,6 +183,6 @@ namespace MediaBrowser.Dlna.Profiles } } }; - } + } } } diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs index fbbb7a594..259d8e9ff 100644 --- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs @@ -1,14 +1,16 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SamsungSmartTvProfile : DefaultProfile { public SamsungSmartTvProfile() { Name = "Samsung Smart TV"; - SupportsAlbumArtInDidl = true; + EnableAlbumArtInDidl = true; Identification = new DeviceIdentification { diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs index cec29b418..04309d55f 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBlurayPlayer2013Profile : DefaultProfile { public SonyBlurayPlayer2013Profile() diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs index 2c678b11f..d9dfc1caf 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBlurayPlayerProfile : DefaultProfile { public SonyBlurayPlayerProfile() diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs index 042cc0a96..cb91de4a0 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBravia2010Profile : DefaultProfile { public SonyBravia2010Profile() @@ -96,13 +98,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile @@ -112,12 +108,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs index 401c40c36..626a91a73 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBravia2011Profile : DefaultProfile { public SonyBravia2011Profile() @@ -138,13 +140,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile @@ -154,12 +150,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs index 2d24c406e..82b6b6d5f 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBravia2012Profile : DefaultProfile { public SonyBravia2012Profile() @@ -126,13 +128,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile @@ -142,12 +138,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs index 10f712958..aec65e98e 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyBravia2013Profile : DefaultProfile { public SonyBravia2013Profile() @@ -182,13 +184,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile @@ -198,12 +194,7 @@ namespace MediaBrowser.Dlna.Profiles 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"} - } + Type = DlnaProfileType.Video }, new MediaProfile diff --git a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs index 39490f806..7502201ea 100644 --- a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class SonyPs3Profile : DefaultProfile { public SonyPs3Profile() diff --git a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs index 47c7b21cc..af5d9b295 100644 --- a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs +++ b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class WdtvLiveProfile : DefaultProfile { public WdtvLiveProfile() diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs index 660d821d3..640317fbc 100644 --- a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class Xbox360Profile : DefaultProfile { public Xbox360Profile() diff --git a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs index 0daa5d7a2..058c69e1f 100644 --- a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs +++ b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs @@ -1,7 +1,9 @@ -using MediaBrowser.Controller.Dlna; +using System.Xml.Serialization; +using MediaBrowser.Controller.Dlna; namespace MediaBrowser.Dlna.Profiles { + [XmlRoot("Profile")] public class XboxOneProfile : DefaultProfile { public XboxOneProfile() diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml new file mode 100644 index 000000000..52b92c6f3 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Generic Device</Name> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,wma" type="Audio" /> + <DirectPlayProfile container="avi,mp4" type="Video" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles /> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml new file mode 100644 index 000000000..3332e4d45 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Denon AVR</Name> + <Identification> + <FriendlyName>Denon:\[AVR:.*</FriendlyName> + <Manufacturer>Denon</Manufacturer> + <Headers /> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles /> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml new file mode 100644 index 000000000..cc8b40430 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml @@ -0,0 +1,73 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>LG Smart TV</Name> + <Identification> + <FriendlyName>LG.*</FriendlyName> + <Headers> + <HttpHeaderInfo name="User-Agent" value="LG" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>10</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="mpeg4"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3,aac,mp3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml new file mode 100644 index 000000000..b19cb0f7b --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Linksys DMA2100</Name> + <Identification> + <ModelName>DMA2100us</ModelName> + <Headers /> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" /> + <DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles /> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml new file mode 100644 index 000000000..71e240313 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Panasonic Viera</Name> + <Identification> + <FriendlyName>VIERA</FriendlyName> + <Manufacturer>Panasonic</Manufacturer> + <Headers> + <HttpHeaderInfo name="User-Agent" value="Panasonic MIL DLNA" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>10</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3" videoCodec="mpeg2video,mpeg4" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="aac,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="pcm" videoCodec="mpeg4" type="Video" /> + <DirectPlayProfile container="flv" audioCodec="aac" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitDepth" value="8" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml new file mode 100644 index 000000000..77648147f --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml @@ -0,0 +1,102 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Samsung Smart TV</Name> + <Identification> + <ModelUrl>samsung.com</ModelUrl> + <Headers /> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca" videoCodec="h264,mpeg4,mjpeg" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="mp3,ac3,dca,aac" videoCodec="h264,mpeg4,mjpeg4" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="mp3,aac" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="3gpp" audioCodec="aac,he-aac" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="mpg,mpeg" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" /> + <DirectPlayProfile container="vro,vob" audioCodec="ac3,mp2,mp3" videoCodec="mpeg1video,mpeg2video" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,eac3" videoCodec="mpeg2video,h264,vc1" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmavoice" videoCodec="wmv2,wmv3" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="mpeg2video"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="30720000" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="mpeg4"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="8192000" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="37500000" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="wmv2,wmv3,vc1"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="25600000" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3,wmav2,dca,aac,mp3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="avi" type="Video" mimeType="video/x-msvideo"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mkv" type="Video" mimeType="video/x-mkv"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml new file mode 100644 index 000000000..942812295 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml @@ -0,0 +1,69 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Blu-ray Player 2013</Name> + <Identification> + <FriendlyName>Blu-ray Disc Player</FriendlyName> + <ModelNumber>BDP-2013</ModelNumber> + <Manufacturer>Sony</Manufacturer> + <Headers /> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;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:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="ac3,aac,pcm,mp3" videoCodec="mpeg4,h264" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml new file mode 100644 index 000000000..519304576 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml @@ -0,0 +1,97 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Blu-ray Player</Name> + <Identification> + <FriendlyName>Blu-ray Disc Player</FriendlyName> + <Manufacturer>Sony</Manufacturer> + <Headers> + <HttpHeaderInfo name="X-AV-Client-Info" value="(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)" match="Regex" /> + <HttpHeaderInfo name="X-AV-Physical-Unit-Info" value="(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)" match="Regex" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>http-get:*:video/divx:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/vnd.dlna.adts:DLNA.ORG_PN=AAC_ADTS_320;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/flac:DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:audio/ogg:DLNA.ORG_PN=OGG;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:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/png:DLNA.ORG_PN=PNG_TN;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:image/gif:DLNA.ORG_PN=GIF_LRG;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_JP_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-flv:DLNA.ORG_PN=FLV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-dvr:DLNA.ORG_PN=DVR_MS;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/wtv:DLNA.ORG_PN=WTV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/ogg:DLNA.ORG_PN=OGV;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/vnd.rn-realvideo:DLNA.ORG_PN=REAL_VIDEO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_3GPP_P0_L10_AMR;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_H263_MP4_P0_L10_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" /> + <DirectPlayProfile container="avi,mp4" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="mpeg2video" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4,vc1" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="avi" type="Video" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mkv" type="Video" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" type="Video" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mp4" type="Video" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mpeg" type="Video" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mp3" type="Audio" mimeType="audio/mpeg"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml new file mode 100644 index 000000000..d240e1d34 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml @@ -0,0 +1,100 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Bravia (2010)</Name> + <Identification> + <FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName> + <Manufacturer>Sony</Manufacturer> + <Headers> + <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[EHLNPB]X\d[01]\d.*" match="Regex" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://www.microsoft.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <SonyAggregationFlags>10</SonyAggregationFlags> + <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</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="mpeg2video"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" /> + <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml new file mode 100644 index 000000000..2372aa5ad --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml @@ -0,0 +1,103 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Bravia (2011)</Name> + <Identification> + <FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName> + <Manufacturer>Sony</Manufacturer> + <Headers> + <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}([A-Z]X\d2\d|CX400).*" match="Regex" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://www.microsoft.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <SonyAggregationFlags>10</SonyAggregationFlags> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="mpeg2video"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="20000000" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" /> + <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml new file mode 100644 index 000000000..7edf09134 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Bravia (2012)</Name> + <Identification> + <FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName> + <Manufacturer>Sony</Manufacturer> + <Headers> + <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[A-Z]X\d5(\d|G).*" match="Regex" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://www.microsoft.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <SonyAggregationFlags>10</SonyAggregationFlags> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml new file mode 100644 index 000000000..ec624cd8e --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony Bravia (2013)</Name> + <Identification> + <FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName> + <Manufacturer>Sony</Manufacturer> + <Headers> + <HttpHeaderInfo name="X-AV-Client-Info" value=".*KDL-\d{2}[WR][5689]\d{2}A.*" match="Regex" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>3.0</ModelNumber> + <ModelUrl>http://www.microsoft.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <SonyAggregationFlags>10</SonyAggregationFlags> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" /> + <DirectPlayProfile container="mp4" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="mov" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4,mjpeg" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="ac3,eac3,aac,mp3,mp2,pcm,vorbis" videoCodec="h264,mpeg4,vp8" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="ac3,eac3,mp3" videoCodec="mpeg4" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="pcm" videoCodec="mjpeg" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="mp4" audioCodec="aac" type="Audio" /> + <DirectPlayProfile container="wav" audioCodec="pcm" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3,aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts"> + <Conditions /> + </MediaProfile> + <MediaProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml new file mode 100644 index 000000000..eeaf2d819 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml @@ -0,0 +1,94 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Sony PlayStation 3</Name> + <Identification> + <FriendlyName>PLAYSTATION 3</FriendlyName> + <Headers> + <HttpHeaderInfo name="User-Agent" value="PLAYSTATION 3" match="Substring" /> + <HttpHeaderInfo name="X-AV-Client-Info" value="PLAYSTATION 3" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <XDlnaDoc>DMS-1.50</XDlnaDoc> + <SonyAggregationFlags>10</SonyAggregationFlags> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,wma" type="Audio" /> + <DirectPlayProfile container="avi,mp4" type="Video" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="AudioBitrate" value="640000" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="wmapro"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" /> + <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="mp4,mov" audioCodec="aac" type="Video" mimeType="video/mp4"> + <Conditions /> + </MediaProfile> + <MediaProfile container="avi" type="Video" orgPn="AVI" mimeType="video/divx"> + <Conditions /> + </MediaProfile> + <MediaProfile container="wav" type="Audio" mimeType="audio/wav"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml new file mode 100644 index 000000000..ffa39c26d --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml @@ -0,0 +1,80 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>WDTV Live</Name> + <Identification> + <ModelName>WD TV HD Live</ModelName> + <Headers> + <HttpHeaderInfo name="User-Agent" value="alphanetworks" match="Substring" /> + <HttpHeaderInfo name="User-Agent" value="ALPHA Networks" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>5</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" /> + <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" /> + <DirectPlayProfile container="mkv" audioCodec="ac3,dca,aac,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" /> + <DirectPlayProfile container="ts" audioCodec="ac3,dca,mp2,mp3" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" /> + <DirectPlayProfile container="mp4,mov" audioCodec="ac3,aac,mp2,mp3" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" /> + <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" /> + <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" /> + <DirectPlayProfile container="flac" audioCodec="flac" type="Audio" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" /> + <DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="true" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="ts" type="Video" orgPn="MPEG_TS_SD_NA"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml new file mode 100644 index 000000000..e7839ca77 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml @@ -0,0 +1,105 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Xbox 360</Name> + <Identification> + <ModelName>Xbox 360</ModelName> + <Headers> + <HttpHeaderInfo name="User-Agent" value="Xbox" match="Substring" /> + <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Microsoft Corporation</Manufacturer> + <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl> + <ModelName>Windows Media Player Sharing</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>12.0</ModelNumber> + <ModelUrl>http://www.microsoft.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <XDlnaDoc>DMS-1.50</XDlnaDoc> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>40</TimelineOffsetSeconds> + <RequiresPlainVideoItems>true</RequiresPlainVideoItems> + <RequiresPlainFolders>true</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" /> + <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" /> + <DirectPlayProfile container="mp4,mov" audioCodec="aac,ac3" videoCodec="h264,mpeg4" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="wmv2,wmv3,vc1" type="Video" /> + <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" /> + <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" /> + <DirectPlayProfile container="jpeg" type="Photo" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="asf" type="Video" videoCodec="wmv2" audioCodec="wmav2" estimateContentLength="true" enableMpegtsM2TsMode="false" transcodeSeekInfo="Bytes"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles> + <ContainerProfile type="Video" container="mp4,mov"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Has64BitOffsets" value="false" isRequired="false" /> + </Conditions> + </ContainerProfile> + <ContainerProfile type="Photo"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + </Conditions> + </ContainerProfile> + </ContainerProfiles> + <CodecProfiles> + <CodecProfile type="VideoCodec" codec="mpeg4"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1280" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="720" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="5120000" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="h264"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="41" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="10240000" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoCodec" codec="wmv2,wmv3,vc1"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" /> + <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoBitrate" value="15360000" isRequired="false" /> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="ac3,wmav2,wmapro"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="false" /> + </Conditions> + </CodecProfile> + <CodecProfile type="VideoAudioCodec" codec="aac"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="false" /> + <ProfileCondition condition="Equals" property="AudioProfile" value="lc" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="avi" type="Video" mimeType="video/avi"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml new file mode 100644 index 000000000..5243218fb --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>Xbox One</Name> + <Identification> + <FriendlyName>Xbox-SystemOS</FriendlyName> + <ModelName>Xbox One</ModelName> + <Headers /> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,wma" type="Audio" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles /> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles> + <MediaProfile container="avi" type="Video" mimeType="video/x-msvideo"> + <Conditions /> + </MediaProfile> + </MediaProfiles> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml new file mode 100644 index 000000000..126d7fe73 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <Name>foobar2000</Name> + <Identification> + <FriendlyName>foobar</FriendlyName> + <Headers> + <HttpHeaderInfo name="User-Agent" value="foobar" match="Substring" /> + </Headers> + </Identification> + <FriendlyName>Media Browser</FriendlyName> + <Manufacturer>Media Browser</Manufacturer> + <ManufacturerUrl>http://mediabrowser3.com/</ManufacturerUrl> + <ModelName>Media Browser</ModelName> + <ModelDescription>Media Browser</ModelDescription> + <ModelNumber>Media Browser</ModelNumber> + <ModelUrl>http://mediabrowser3.com/</ModelUrl> + <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests> + <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl> + <SupportedMediaTypes>Audio</SupportedMediaTypes> + <ProtocolInfo>DLNA</ProtocolInfo> + <TimelineOffsetSeconds>0</TimelineOffsetSeconds> + <RequiresPlainVideoItems>false</RequiresPlainVideoItems> + <RequiresPlainFolders>false</RequiresPlainFolders> + <DirectPlayProfiles> + <DirectPlayProfile container="mp3,wma" type="Audio" /> + <DirectPlayProfile container="avi,mp4" type="Video" /> + </DirectPlayProfiles> + <TranscodingProfiles> + <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings /> + </TranscodingProfile> + <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto"> + <Settings> + <TranscodingSetting name="VideoProfile" value="baseline" /> + </Settings> + </TranscodingProfile> + </TranscodingProfiles> + <ContainerProfiles /> + <CodecProfiles> + <CodecProfile type="VideoCodec"> + <Conditions> + <ProfileCondition condition="LessThanEqual" property="VideoLevel" value="3" isRequired="false" /> + </Conditions> + </CodecProfile> + </CodecProfiles> + <MediaProfiles /> +</Profile>
\ No newline at end of file diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 960b0f635..9aefb4f1c 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -101,6 +101,9 @@ <Compile Include="..\MediaBrowser.Model\Configuration\UserConfiguration.cs"> <Link>Configuration\UserConfiguration.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Dlna\DeviceProfileInfo.cs"> + <Link>Dlna\DeviceProfileInfo.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs"> <Link>Drawing\DrawingUtils.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index b010ad9c9..ce2a7600f 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -88,6 +88,9 @@ <Compile Include="..\MediaBrowser.Model\Configuration\UserConfiguration.cs"> <Link>Configuration\UserConfiguration.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Dlna\DeviceProfileInfo.cs"> + <Link>Dlna\DeviceProfileInfo.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Drawing\DrawingUtils.cs"> <Link>Drawing\DrawingUtils.cs</Link> </Compile> diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 1f304112f..d0caa3ad2 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -58,6 +58,12 @@ namespace MediaBrowser.Model.Configuration public string ItemsByNamePath { get; set; } /// <summary> + /// Gets or sets the metadata path. + /// </summary> + /// <value>The metadata path.</value> + public string MetadataPath { get; set; } + + /// <summary> /// Gets or sets the display name of the season zero. /// </summary> /// <value>The display name of the season zero.</value> diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 2145860c7..10f984f88 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -52,6 +52,7 @@ namespace MediaBrowser.Model.Configuration public bool EnableLiveTvAccess { get; set; } public bool EnableMediaPlayback { get; set; } + public bool EnableContentDeletion { get; set; } public string[] BlockedMediaFolders { get; set; } @@ -63,8 +64,9 @@ namespace MediaBrowser.Model.Configuration public UserConfiguration() { IsAdministrator = true; - EnableRemoteControlOfOtherUsers = true; + EnableRemoteControlOfOtherUsers = true; + EnableContentDeletion = true; EnableLiveTvManagement = true; EnableMediaPlayback = true; EnableLiveTvAccess = true; diff --git a/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs new file mode 100644 index 000000000..ceb27386c --- /dev/null +++ b/MediaBrowser.Model/Dlna/DeviceProfileInfo.cs @@ -0,0 +1,30 @@ + +namespace MediaBrowser.Model.Dlna +{ + public class DeviceProfileInfo + { + /// <summary> + /// Gets or sets the identifier. + /// </summary> + /// <value>The identifier.</value> + public string Id { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + /// <value>The name.</value> + public string Name { get; set; } + + /// <summary> + /// Gets or sets the type. + /// </summary> + /// <value>The type.</value> + public DeviceProfileType Type { get; set; } + } + + public enum DeviceProfileType + { + System = 0, + User = 1 + } +} diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index a8f751c10..b644661f4 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -124,6 +124,12 @@ namespace MediaBrowser.Model.Entities public string Path { get; set; } /// <summary> + /// Gets or sets the pixel format. + /// </summary> + /// <value>The pixel format.</value> + public string PixelFormat { get; set; } + + /// <summary> /// Gets or sets the level. /// </summary> /// <value>The level.</value> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 5e9b97939..bf29b4bff 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -66,6 +66,7 @@ <Compile Include="Configuration\MetadataPlugin.cs" /> <Compile Include="Configuration\MetadataOptions.cs" /> <Compile Include="Configuration\ServerConfiguration.cs" /> + <Compile Include="Dlna\DeviceProfileInfo.cs" /> <Compile Include="Drawing\ImageOutputFormat.cs" /> <Compile Include="Dto\BaseItemPerson.cs" /> <Compile Include="Dto\ChapterInfoDto.cs" /> diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 044973064..75a9d9c36 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -50,12 +50,16 @@ namespace MediaBrowser.Providers.MediaInfo return ItemUpdateType.MetadataImport; } + private const string SchemaVersion = "1"; + private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var idString = item.Id.ToString("N"); - var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-audio", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); + var cachePath = Path.Combine(_appPaths.CachePath, + "ffprobe-audio", + idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); try { @@ -148,7 +152,7 @@ namespace MediaBrowser.Providers.MediaInfo if (!string.IsNullOrWhiteSpace(composer)) { - foreach (var person in Split(composer)) + foreach (var person in Split(composer, false)) { audio.AddPerson(new PersonInfo { Name = person, Type = PersonType.Composer }); } @@ -221,12 +225,15 @@ namespace MediaBrowser.Providers.MediaInfo /// Splits the specified val. /// </summary> /// <param name="val">The val.</param> + /// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param> /// <returns>System.String[][].</returns> - private IEnumerable<string> Split(string val) + private IEnumerable<string> Split(string val, bool allowCommaDelimiter) { // Only use the comma as a delimeter if there are no slashes or pipes. // We want to be careful not to split names that have commas in them - var delimeter = _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? _nameDelimiters : new[] { ',' }; + var delimeter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? + _nameDelimiters : + new[] { ',' }; return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries) .Where(i => !string.IsNullOrWhiteSpace(i)) @@ -312,7 +319,7 @@ namespace MediaBrowser.Providers.MediaInfo if (!string.IsNullOrEmpty(val)) { // Sometimes the artist name is listed here, account for that - var studios = Split(val).Where(i => !audio.HasArtist(i)); + var studios = Split(val, true).Where(i => !audio.HasArtist(i)); foreach (var studio in studios) { @@ -334,7 +341,7 @@ namespace MediaBrowser.Providers.MediaInfo { audio.Genres.Clear(); - foreach (var genre in Split(val)) + foreach (var genre in Split(val, true)) { audio.AddGenre(genre); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index d516a8221..58fe7f66d 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -107,6 +107,8 @@ namespace MediaBrowser.Providers.MediaInfo return ItemUpdateType.MetadataImport; } + private const string SchemaVersion = "1"; + private async Task<InternalMediaInfoResult> GetMediaInfo(BaseItem item, IIsoMount isoMount, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -114,7 +116,9 @@ namespace MediaBrowser.Providers.MediaInfo cancellationToken.ThrowIfCancellationRequested(); var idString = item.Id.ToString("N"); - var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-video", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); + var cachePath = Path.Combine(_appPaths.CachePath, + "ffprobe-video", + idString.Substring(0, 2), idString, "v" + SchemaVersion + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json"); try { @@ -161,7 +165,8 @@ namespace MediaBrowser.Providers.MediaInfo var mediaStreams = MediaEncoderHelpers.GetMediaInfo(data).MediaStreams; - var chapters = data.Chapters ?? new List<ChapterInfo>(); + var mediaChapters = (data.Chapters ?? new MediaChapter[] { }).ToList(); + var chapters = mediaChapters.Select(GetChapterInfo).ToList(); if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay)) { @@ -200,6 +205,24 @@ namespace MediaBrowser.Providers.MediaInfo await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false); } + private ChapterInfo GetChapterInfo(MediaChapter chapter) + { + var info = new ChapterInfo(); + + if (chapter.tags != null) + { + string name; + if (chapter.tags.TryGetValue("title", out name)) + { + info.Name = name; + } + } + + info.StartPositionTicks = chapter.start/100; + + return info; + } + private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo) { var video = (Video)item; diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs index 415205cb1..cb3621fd1 100644 --- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.Configuration { UpdateItemsByNamePath(); UpdateTranscodingTempPath(); + UpdateMetadataPath(); } /// <summary> @@ -77,6 +78,16 @@ namespace MediaBrowser.Server.Implementations.Configuration } /// <summary> + /// Updates the metadata path. + /// </summary> + private void UpdateMetadataPath() + { + ((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath = string.IsNullOrEmpty(Configuration.MetadataPath) ? + null : + Configuration.MetadataPath; + } + + /// <summary> /// Updates the transcoding temporary path. /// </summary> private void UpdateTranscodingTempPath() @@ -98,6 +109,7 @@ namespace MediaBrowser.Server.Implementations.Configuration ValidateItemByNamePath(newConfig); ValidateTranscodingTempPath(newConfig); ValidatePathSubstitutions(newConfig); + ValidateMetadataPath(newConfig); base.ReplaceConfiguration(newConfiguration); } @@ -166,5 +178,25 @@ namespace MediaBrowser.Server.Implementations.Configuration } } } + + /// <summary> + /// Validates the metadata path. + /// </summary> + /// <param name="newConfig">The new configuration.</param> + /// <exception cref="System.IO.DirectoryNotFoundException"></exception> + private void ValidateMetadataPath(ServerConfiguration newConfig) + { + var newPath = newConfig.MetadataPath; + + if (!string.IsNullOrWhiteSpace(newPath) + && !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath)) + { + // Validate + if (!Directory.Exists(newPath)) + { + throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath)); + } + } + } } } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 06028d37e..2ee843f09 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -260,6 +260,8 @@ namespace MediaBrowser.Server.Implementations.Library public event EventHandler<GenericEventArgs<User>> UserCreated; + private readonly SemaphoreSlim _userListLock = new SemaphoreSlim(1, 1); + /// <summary> /// Creates the user. /// </summary> @@ -279,19 +281,28 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name)); } - var user = InstantiateNewUser(name); + await _userListLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); - var list = Users.ToList(); - list.Add(user); - Users = list; + try + { + var user = InstantiateNewUser(name); - user.DateLastSaved = DateTime.UtcNow; + var list = Users.ToList(); + list.Add(user); + Users = list; - await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); + user.DateLastSaved = DateTime.UtcNow; - EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger); + await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); - return user; + EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger); + + return user; + } + finally + { + _userListLock.Release(); + } } /// <summary> @@ -325,23 +336,32 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Name)); } - await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); - - var path = user.ConfigurationFilePath; + await _userListLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); try { - File.Delete(path); + await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); + + var path = user.ConfigurationFilePath; + + try + { + File.Delete(path); + } + catch (IOException ex) + { + _logger.ErrorException("Error deleting file {0}", ex, path); + } + + // Force this to be lazy loaded again + Users = await LoadUsers().ConfigureAwait(false); + + OnUserDeleted(user); } - catch (IOException ex) + finally { - _logger.ErrorException("Error deleting file {0}", ex, path); + _userListLock.Release(); } - - // Force this to be lazy loaded again - Users = await LoadUsers().ConfigureAwait(false); - - OnUserDeleted(user); } /// <summary> diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 6a4c3930a..db8786d62 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1498,8 +1498,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var programs = _programs.ToList(); - var startDate = programs.Select(i => i.Value.StartDate).Min(); - var endDate = programs.Select(i => i.Value.StartDate).Max(); + var startDate = _programs.Count == 0 ? DateTime.MinValue : + programs.Select(i => i.Value.StartDate).Min(); + + var endDate = programs.Count == 0 ? DateTime.MinValue : + programs.Select(i => i.Value.StartDate).Max(); return new GuideInfo { diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index fddba7662..c646d80bc 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -175,6 +175,10 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder string probeSizeArgument, CancellationToken cancellationToken) { + var args = extractChapters + ? "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_chapters -show_format" + : "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format"; + var process = new Process { StartInfo = new ProcessStartInfo @@ -186,8 +190,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder RedirectStandardOutput = true, RedirectStandardError = true, FileName = FFProbePath, - Arguments = string.Format( - "{0} -i {1} -threads 0 -v info -print_format json -show_streams -show_format", + Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(), WindowStyle = ProcessWindowStyle.Hidden, @@ -204,7 +207,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); InternalMediaInfoResult result; - string standardError = null; try { @@ -221,24 +223,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder try { - Task<string> standardErrorReadTask = null; - - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - if (extractChapters) - { - standardErrorReadTask = process.StandardError.ReadToEndAsync(); - } - else - { - process.BeginErrorReadLine(); - } + process.BeginErrorReadLine(); result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream); - - if (extractChapters) - { - standardError = await standardErrorReadTask.ConfigureAwait(false); - } } catch { @@ -282,11 +269,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder } } - if (extractChapters && !string.IsNullOrEmpty(standardError)) - { - AddChapters(result, standardError); - } - return result; } @@ -296,66 +278,6 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <summary> - /// Adds the chapters. - /// </summary> - /// <param name="result">The result.</param> - /// <param name="standardError">The standard error.</param> - private void AddChapters(InternalMediaInfoResult result, string standardError) - { - var lines = standardError.Split('\n').Select(l => l.TrimStart()); - - var chapters = new List<ChapterInfo>(); - - ChapterInfo lastChapter = null; - - foreach (var line in lines) - { - if (line.StartsWith("Chapter", StringComparison.OrdinalIgnoreCase)) - { - // Example: - // Chapter #0.2: start 400.534, end 4565.435 - const string srch = "start "; - var start = line.IndexOf(srch, StringComparison.OrdinalIgnoreCase); - - if (start == -1) - { - continue; - } - - var subString = line.Substring(start + srch.Length); - subString = subString.Substring(0, subString.IndexOf(',')); - - double seconds; - - if (double.TryParse(subString, NumberStyles.Any, UsCulture, out seconds)) - { - lastChapter = new ChapterInfo - { - StartPositionTicks = TimeSpan.FromSeconds(seconds).Ticks - }; - - chapters.Add(lastChapter); - } - } - - else if (line.StartsWith("title", StringComparison.OrdinalIgnoreCase)) - { - if (lastChapter != null && string.IsNullOrEmpty(lastChapter.Name)) - { - var index = line.IndexOf(':'); - - if (index != -1) - { - lastChapter.Name = line.Substring(index + 1).Trim().TrimEnd('\r'); - } - } - } - } - - result.Chapters = chapters; - } - - /// <summary> /// Processes the exited. /// </summary> /// <param name="sender">The sender.</param> diff --git a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs index c36c49df0..df2a5f83c 100644 --- a/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs +++ b/MediaBrowser.Server.Implementations/ServerApplicationPaths.cs @@ -1,6 +1,6 @@ -using System; -using MediaBrowser.Common.Implementations; +using MediaBrowser.Common.Implementations; using MediaBrowser.Controller; +using System; using System.IO; namespace MediaBrowser.Server.Implementations @@ -239,14 +239,20 @@ namespace MediaBrowser.Server.Implementations } } + private string _internalMetadataPath; public string InternalMetadataPath { get { - return Path.Combine(DataPath, "metadata"); + return _internalMetadataPath ?? (_internalMetadataPath = Path.Combine(DataPath, "metadata")); + } + set + { + _internalMetadataPath = value; } } + public string GetInternalMetadataPath(Guid id) { var idString = id.ToString("N"); diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 93b9b87c6..06ffa37a1 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -442,7 +442,7 @@ namespace MediaBrowser.ServerApplication FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false); RegisterSingleInstance(FileOrganizationRepository); - UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository); + UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository); RegisterSingleInstance(UserManager); LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager); @@ -466,13 +466,13 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(HttpServer, false); progress.Report(10); - ServerManager = new ServerManager(this, JsonSerializer, Logger, ServerConfigurationManager); + ServerManager = new ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager); RegisterSingleInstance(ServerManager); LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager); RegisterSingleInstance(LocalizationManager); - ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); + ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer); RegisterSingleInstance(ImageProcessor); DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager); @@ -481,7 +481,7 @@ namespace MediaBrowser.ServerApplication var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); RegisterSingleInstance<INewsService>(newsService); - var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager); + var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, LogManager.GetLogger("FileOrganizationService"), LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager, ProviderManager); RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService); progress.Report(15); @@ -502,7 +502,7 @@ namespace MediaBrowser.ServerApplication var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance<IAppThemeManager>(appThemeManager); - var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, JsonSerializer); + var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("DLNA")); RegisterSingleInstance<IDlnaManager>(dlnaManager); var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor); @@ -801,7 +801,7 @@ namespace MediaBrowser.ServerApplication list.Add(typeof(ApiEntryPoint).Assembly); // Include composable parts in the Dashboard assembly - list.Add(typeof(DashboardInfo).Assembly); + list.Add(typeof(DashboardService).Assembly); // Include composable parts in the Model assembly list.Add(typeof(SystemInfo).Assembly); diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfo.cs b/MediaBrowser.WebDashboard/Api/DashboardInfo.cs deleted file mode 100644 index 78cc5a758..000000000 --- a/MediaBrowser.WebDashboard/Api/DashboardInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MediaBrowser.Model.Session; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Tasks; -using System; -using System.Collections.Generic; - -namespace MediaBrowser.WebDashboard.Api -{ - /// <summary> - /// Class DashboardInfo - /// </summary> - public class DashboardInfo - { - /// <summary> - /// Gets or sets the system info. - /// </summary> - /// <value>The system info.</value> - public SystemInfo SystemInfo { get; set; } - - /// <summary> - /// Gets or sets the running tasks. - /// </summary> - /// <value>The running tasks.</value> - public List<TaskInfo> RunningTasks { get; set; } - - /// <summary> - /// Gets or sets the application update task id. - /// </summary> - /// <value>The application update task id.</value> - public Guid ApplicationUpdateTaskId { get; set; } - - /// <summary> - /// Gets or sets the active connections. - /// </summary> - /// <value>The active connections.</value> - public List<SessionInfoDto> ActiveConnections { get; set; } - } - -} diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs deleted file mode 100644 index af0f9e3a0..000000000 --- a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs +++ /dev/null @@ -1,62 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Logging; -using System.Threading.Tasks; - -namespace MediaBrowser.WebDashboard.Api -{ - /// <summary> - /// Class DashboardInfoWebSocketListener - /// </summary> - class DashboardInfoWebSocketListener : BasePeriodicWebSocketListener<DashboardInfo, object> - { - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - protected override string Name - { - get { return "DashboardInfo"; } - } - - private readonly IServerApplicationHost _appHost; - - /// <summary> - /// Gets or sets the task manager. - /// </summary> - /// <value>The task manager.</value> - private readonly ITaskManager _taskManager; - - private readonly ISessionManager _sessionManager; - private readonly IDtoService _dtoService; - - /// <summary> - /// Initializes a new instance of the <see cref="DashboardInfoWebSocketListener" /> class. - /// </summary> - /// <param name="appHost">The app host.</param> - /// <param name="logger">The logger.</param> - /// <param name="taskManager">The task manager.</param> - /// <param name="sessionManager">The session manager.</param> - public DashboardInfoWebSocketListener(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, ISessionManager sessionManager, IDtoService dtoService) - : base(logger) - { - _appHost = appHost; - _taskManager = taskManager; - _sessionManager = sessionManager; - _dtoService = dtoService; - } - - /// <summary> - /// Gets the data to send. - /// </summary> - /// <param name="state">The state.</param> - /// <returns>Task{IEnumerable{TaskInfo}}.</returns> - protected override Task<DashboardInfo> GetDataToSend(object state) - { - return Task.FromResult(DashboardService.GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService)); - } - } -} diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 88f86632b..99afbbdd7 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -1,16 +1,13 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; -using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Tasks; using ServiceStack; +using ServiceStack.Web; using System; using System.Collections.Generic; using System.IO; @@ -18,7 +15,6 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using ServiceStack.Web; namespace MediaBrowser.WebDashboard.Api { @@ -67,14 +63,6 @@ namespace MediaBrowser.WebDashboard.Api } /// <summary> - /// Class GetDashboardInfo - /// </summary> - [Route("/dashboard/dashboardInfo", "GET")] - public class GetDashboardInfo : IReturn<DashboardInfo> - { - } - - /// <summary> /// Class DashboardService /// </summary> public class DashboardService : IRestfulService, IHasResultFactory @@ -98,12 +86,6 @@ namespace MediaBrowser.WebDashboard.Api public IRequest Request { get; set; } /// <summary> - /// Gets or sets the task manager. - /// </summary> - /// <value>The task manager.</value> - private readonly ITaskManager _taskManager; - - /// <summary> /// The _app host /// </summary> private readonly IServerApplicationHost _appHost; @@ -113,24 +95,18 @@ namespace MediaBrowser.WebDashboard.Api /// </summary> private readonly IServerConfigurationManager _serverConfigurationManager; - private readonly ISessionManager _sessionManager; - private readonly IDtoService _dtoService; private readonly IFileSystem _fileSystem; /// <summary> /// Initializes a new instance of the <see cref="DashboardService" /> class. /// </summary> - /// <param name="taskManager">The task manager.</param> /// <param name="appHost">The app host.</param> /// <param name="serverConfigurationManager">The server configuration manager.</param> - /// <param name="sessionManager">The session manager.</param> - public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IDtoService dtoService, IFileSystem fileSystem) + /// <param name="fileSystem">The file system.</param> + public DashboardService(IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem) { - _taskManager = taskManager; _appHost = appHost; _serverConfigurationManager = serverConfigurationManager; - _sessionManager = sessionManager; - _dtoService = dtoService; _fileSystem = fileSystem; } @@ -168,45 +144,6 @@ namespace MediaBrowser.WebDashboard.Api /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> - public object Get(GetDashboardInfo request) - { - var result = GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService); - - return ResultFactory.GetOptimizedResult(Request, result); - } - - /// <summary> - /// Gets the dashboard info. - /// </summary> - /// <param name="appHost">The app host.</param> - /// <param name="taskManager">The task manager.</param> - /// <param name="connectionManager">The connection manager.</param> - /// <returns>DashboardInfo.</returns> - public static DashboardInfo GetDashboardInfo(IServerApplicationHost appHost, - ITaskManager taskManager, - ISessionManager connectionManager, IDtoService dtoService) - { - var connections = connectionManager.Sessions.Where(i => i.IsActive).ToList(); - - return new DashboardInfo - { - SystemInfo = appHost.GetSystemInfo(), - - RunningTasks = taskManager.ScheduledTasks.Where(i => i.State == TaskState.Running || i.State == TaskState.Cancelling) - .Select(ScheduledTaskHelpers.GetTaskInfo) - .ToList(), - - ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.ScheduledTask.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id, - - ActiveConnections = connections.Select(dtoService.GetSessionInfoDto).ToList() - }; - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> public object Get(GetDashboardConfigurationPage request) { var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase)); @@ -473,6 +410,7 @@ namespace MediaBrowser.WebDashboard.Api "alphapicker.js", "addpluginpage.js", "advancedconfigurationpage.js", + "advancedpaths.js", "advancedserversettings.js", "metadataadvanced.js", "appsplayback.js", @@ -484,6 +422,8 @@ namespace MediaBrowser.WebDashboard.Api "dashboardinfo.js", "dashboardpage.js", "directorybrowser.js", + "dlnaprofile.js", + "dlnaprofiles.js", "dlnasettings.js", "editcollectionitems.js", "edititemmetadata.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index a0dbae3d4..6a8cc49b1 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -63,9 +63,7 @@ <Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Api\ConfigurationPageInfo.cs" />
- <Compile Include="Api\DashboardInfo.cs" />
<Compile Include="Api\DashboardService.cs" />
- <Compile Include="Api\DashboardInfoWebSocketListener.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServerEntryPoint.cs" />
</ItemGroup>
@@ -85,6 +83,9 @@ </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ApiClient.js" />
+ <Content Include="dashboard-ui\advancedpaths.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\advancedserversettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -202,8 +203,12 @@ <Content Include="dashboard-ui\css\images\items\list\remotesearch.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\media\pause.png" />
- <Content Include="dashboard-ui\css\images\media\play.png" />
+ <Content Include="dashboard-ui\css\images\media\pause.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\css\images\media\play.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\css\images\media\tvflyout.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -219,6 +224,12 @@ <Content Include="dashboard-ui\dashboardinfopage.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\dlnaprofile.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\dlnaprofiles.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\dlnasettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -483,6 +494,9 @@ <Content Include="dashboard-ui\livetvrecordings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\advancedpaths.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\advancedserversettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -504,6 +518,12 @@ <Content Include="dashboard-ui\scripts\dashboardinfo.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\dlnaprofile.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\scripts\dlnaprofiles.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\dlnasettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
|
