diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs index 9c9e14ec6..87b97863b 100644 --- a/Emby.Common.Implementations/BaseApplicationHost.cs +++ b/Emby.Common.Implementations/BaseApplicationHost.cs @@ -161,12 +161,6 @@ namespace Emby.Common.Implementations /// The name. public abstract string Name { get; } - /// - /// Gets a value indicating whether this instance is running as service. - /// - /// true if this instance is running as service; otherwise, false. - public abstract bool IsRunningAsService { get; } - protected ICryptoProvider CryptographyProvider = new CryptographyProvider(); protected IEnvironmentInfo EnvironmentInfo { get; private set; } diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index 78070a5d9..3fe20f659 100644 --- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs @@ -20,10 +20,13 @@ namespace Emby.Common.Implementations.IO private readonly List _shortcutHandlers = new List(); private bool EnableFileSystemRequestConcat = true; - public ManagedFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool enableManagedInvalidFileNameChars, bool enableFileSystemRequestConcat) + private string _tempPath; + + public ManagedFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool enableManagedInvalidFileNameChars, bool enableFileSystemRequestConcat, string tempPath) { Logger = logger; _supportsAsyncFileStreams = supportsAsyncFileStreams; + _tempPath = tempPath; EnableFileSystemRequestConcat = enableFileSystemRequestConcat; SetInvalidFileNameChars(enableManagedInvalidFileNameChars); } @@ -487,18 +490,37 @@ namespace Emby.Common.Implementations.IO throw new ArgumentNullException("file2"); } - var temp1 = Path.GetTempFileName(); + var temp1 = Path.Combine(_tempPath, Guid.NewGuid().ToString("N")); // Copying over will fail against hidden files SetHidden(file1, false); SetHidden(file2, false); + Directory.CreateDirectory(_tempPath); CopyFile(file1, temp1, true); CopyFile(file2, file1, true); CopyFile(temp1, file2, true); } + public bool AreEqual(string path1, string path2) + { + if (path1 == null && path2 == null) + { + return true; + } + + if (path1 == null || path2 == null) + { + return false; + } + + path1 = path1.TrimEnd(DirectorySeparatorChar); + path2 = path2.TrimEnd(DirectorySeparatorChar); + + return string.Equals(path1, path2, StringComparison.OrdinalIgnoreCase); + } + public bool ContainsSubPath(string parentPath, string path) { if (string.IsNullOrEmpty(parentPath)) @@ -656,21 +678,7 @@ namespace Emby.Common.Implementations.IO private IEnumerable ToMetadata(string parentPath, IEnumerable infos) { - return infos.Select(i => - { - try - { - return GetFileSystemMetadata(i); - } - catch (PathTooLongException) - { - // Can't log using the FullName because it will throw the PathTooLongExceptiona again - //Logger.Warn("Path too long: {0}", i.FullName); - Logger.Warn("File or directory path too long. Parent folder: {0}", parentPath); - return null; - } - - }).Where(i => i != null); + return infos.Select(GetFileSystemMetadata); } public string[] ReadAllLines(string path) diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 5718cbd09..2251a8f58 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -260,7 +260,7 @@ namespace Emby.Dlna.ContentDirectory { totalCount = 1; - if (item.IsFolder || serverItem.StubType.HasValue) + if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue) { var childrenResult = (await GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount).ConfigureAwait(false)); @@ -285,7 +285,7 @@ namespace Emby.Dlna.ContentDirectory var childItem = i.Item; var displayStubType = i.StubType; - if (childItem.IsFolder || displayStubType.HasValue) + if (childItem.IsDisplayedAsFolder || displayStubType.HasValue) { var childCount = (await GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0).ConfigureAwait(false)) .TotalRecordCount; @@ -381,7 +381,7 @@ namespace Emby.Dlna.ContentDirectory foreach (var i in childrenResult.Items) { - if (i.IsFolder) + if (i.IsDisplayedAsFolder) { var childCount = (await GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0).ConfigureAwait(false)) .TotalRecordCount; diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 3e47362f6..ca4c3b912 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -176,6 +176,18 @@ namespace Emby.Dlna.Didl return new NullLogger(); } + private string GetMimeType(string input) + { + var mime = MimeTypes.GetMimeType(input); + + if (string.Equals(mime, "video/mp2t", StringComparison.OrdinalIgnoreCase)) + { + mime = "video/mpeg"; + } + + return mime; + } + private void AddVideoResource(DlnaOptions options, XmlWriter writer, IHasMediaSources video, string deviceId, Filter filter, StreamInfo streamInfo = null) { if (streamInfo == null) @@ -360,7 +372,7 @@ namespace Emby.Dlna.Didl var filename = url.Substring(0, url.IndexOf('?')); var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType) - ? MimeTypes.GetMimeType(filename) + ? GetMimeType(filename) : mediaProfile.MimeType; writer.WriteAttributeString("protocolInfo", String.Format( @@ -481,7 +493,7 @@ namespace Emby.Dlna.Didl var filename = url.Substring(0, url.IndexOf('?')); var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType) - ? MimeTypes.GetMimeType(filename) + ? GetMimeType(filename) : mediaProfile.MimeType; var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container, @@ -674,7 +686,7 @@ namespace Emby.Dlna.Didl writer.WriteStartElement("upnp", "class", NS_UPNP); - if (item.IsFolder || stubType.HasValue) + if (item.IsDisplayedAsFolder || stubType.HasValue) { string classType = null; @@ -760,7 +772,7 @@ namespace Emby.Dlna.Didl // Seeing some LG models locking up due content with large lists of people // The actual issue might just be due to processing a more metadata than it can handle - var limit = 10; + var limit = 6; foreach (var actor in people) { @@ -1007,7 +1019,7 @@ namespace Emby.Dlna.Didl writer.WriteAttributeString("protocolInfo", String.Format( "http-get:*:{0}:{1}", - MimeTypes.GetMimeType("file." + format), + GetMimeType("file." + format), contentFeatures )); diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 4daaa5046..020038422 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -595,6 +595,7 @@ namespace Emby.Dlna new LinksysDMA2100Profile(), new LgTvProfile(), new Foobar2000Profile(), + new SharpSmartTvProfile(), new MediaMonkeyProfile(), //new Windows81Profile(), //new WindowsMediaCenterProfile(), diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index c83aaecab..a8c05a527 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -92,6 +92,7 @@ + @@ -148,7 +149,9 @@ RSSDP - + + + diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index f6be47989..e22298010 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -112,7 +112,7 @@ namespace Emby.Dlna.PlayTo private int GetInactiveTimerIntervalMs() { - return 20000; + return 30000; } public void Start() @@ -440,6 +440,11 @@ namespace Emby.Dlna.PlayTo { var transportState = await GetTransportInfo().ConfigureAwait(false); + if (_disposed) + { + return; + } + DateLastActivity = DateTime.UtcNow; if (transportState.HasValue) @@ -530,6 +535,11 @@ namespace Emby.Dlna.PlayTo private async Task GetVolume() { + if (_disposed) + { + return; + } + var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume"); if (command == null) return; @@ -563,6 +573,11 @@ namespace Emby.Dlna.PlayTo private async Task GetMute() { + if (_disposed) + { + return; + } + var command = RendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMute"); if (command == null) return; @@ -793,6 +808,11 @@ namespace Emby.Dlna.PlayTo private async Task GetAVProtocolAsync() { + if (_disposed) + { + return; + } + var avService = GetAvTransportService(); if (avService == null) return; @@ -807,6 +827,11 @@ namespace Emby.Dlna.PlayTo private async Task GetRenderingProtocolAsync() { + if (_disposed) + { + return; + } + var avService = GetServiceRenderingControl(); if (avService == null) diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 4ad62216e..3c07e95db 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -149,6 +149,11 @@ namespace Emby.Dlna.PlayTo async void _device_MediaChanged(object sender, MediaChangedEventArgs e) { + if (_disposed) + { + return; + } + try { var streamInfo = await StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false); @@ -176,6 +181,11 @@ namespace Emby.Dlna.PlayTo async void _device_PlaybackStopped(object sender, PlaybackStoppedEventArgs e) { + if (_disposed) + { + return; + } + try { var streamInfo = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager) @@ -239,6 +249,11 @@ namespace Emby.Dlna.PlayTo async void _device_PlaybackStart(object sender, PlaybackStartEventArgs e) { + if (_disposed) + { + return; + } + try { var info = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false); @@ -258,6 +273,11 @@ namespace Emby.Dlna.PlayTo async void _device_PlaybackProgress(object sender, PlaybackProgressEventArgs e) { + if (_disposed) + { + return; + } + try { var info = await StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager).ConfigureAwait(false); diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index a93f7da14..962a982c1 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -43,6 +43,7 @@ namespace Emby.Dlna.PlayTo private readonly List _nonRendererUrls = new List(); private DateTime _lastRendererClear; + private bool _disposed; public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory) { @@ -70,6 +71,11 @@ namespace Emby.Dlna.PlayTo async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs e) { + if (_disposed) + { + return; + } + var info = e.Argument; string usn; @@ -121,6 +127,11 @@ namespace Emby.Dlna.PlayTo } } + if (_disposed) + { + return; + } + _logger.Debug("Logging session activity from location {0}", location); var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null) .ConfigureAwait(false); @@ -129,6 +140,11 @@ namespace Emby.Dlna.PlayTo if (controller == null) { + if (_disposed) + { + return; + } + string serverAddress; if (info.LocalIpAddress == null) { @@ -187,6 +203,11 @@ namespace Emby.Dlna.PlayTo catch (Exception ex) { _logger.ErrorException("Error creating PlayTo device.", ex); + + lock (_nonRendererUrls) + { + _nonRendererUrls.Add(location); + } } } @@ -202,6 +223,7 @@ namespace Emby.Dlna.PlayTo public void Dispose() { + _disposed = true; _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered; } } diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs index ff30f2e15..c670f268e 100644 --- a/Emby.Dlna/Profiles/DefaultProfile.cs +++ b/Emby.Dlna/Profiles/DefaultProfile.cs @@ -64,7 +64,7 @@ namespace Emby.Dlna.Profiles { new DirectPlayProfile { - Container = "m4v,ts,mkv,avi,mpg,mpeg,mp4", + Container = "m4v,ts,mpegts,mkv,avi,mpg,mpeg,mp4,mov", VideoCodec = "h264", AudioCodec = "aac,mp3,ac3", Type = DlnaProfileType.Video @@ -72,7 +72,7 @@ namespace Emby.Dlna.Profiles new DirectPlayProfile { - Container = "mp3,wma,aac,wav", + Container = "mp3,wma,aac,wav,flac", Type = DlnaProfileType.Audio } }; diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs index d494a7bfc..89e0697c1 100644 --- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs +++ b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs @@ -23,7 +23,7 @@ namespace Emby.Dlna.Profiles { Match = HeaderMatchType.Substring, Name = "User-Agent", - Value ="XiP" + Value ="Zip_" } } }; @@ -63,22 +63,7 @@ namespace Emby.Dlna.Profiles new DirectPlayProfile { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "alac", - AudioCodec = "alac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Container = "flac", - AudioCodec = "flac", + Container = "mp3,alac,flac", Type = DlnaProfileType.Audio }, diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs index f7cf7b9a1..71f684ec4 100644 --- a/Emby.Dlna/Profiles/LgTvProfile.cs +++ b/Emby.Dlna/Profiles/LgTvProfile.cs @@ -67,7 +67,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "aac,ac3,mp3,dca,dts", Type = DlnaProfileType.Video @@ -203,7 +203,15 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = new ResponseProfile[] + { + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" + } + }; } } } diff --git a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs index 4a4ecdc58..2b31ab55f 100644 --- a/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs +++ b/Emby.Dlna/Profiles/LinksysDMA2100Profile.cs @@ -26,12 +26,20 @@ namespace Emby.Dlna.Profiles new DirectPlayProfile { - Container = "avi,mp4,mkv,ts", + Container = "avi,mp4,mkv,ts,m4v", Type = DlnaProfileType.Video } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = new ResponseProfile[] + { + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" + } + }; } } } diff --git a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs index f3d7f5951..63c7e3a8e 100644 --- a/Emby.Dlna/Profiles/PanasonicVieraProfile.cs +++ b/Emby.Dlna/Profiles/PanasonicVieraProfile.cs @@ -80,7 +80,7 @@ namespace Emby.Dlna.Profiles new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264", AudioCodec = "aac,ac3,mp3,pcm", Type = DlnaProfileType.Video @@ -208,6 +208,12 @@ namespace Emby.Dlna.Profiles Container = "ts", OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", MimeType = "video/vnd.dlna.mpeg-tts" + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; } diff --git a/Emby.Dlna/Profiles/PopcornHourProfile.cs b/Emby.Dlna/Profiles/PopcornHourProfile.cs index 0095c80a2..d13b5c6ad 100644 --- a/Emby.Dlna/Profiles/PopcornHourProfile.cs +++ b/Emby.Dlna/Profiles/PopcornHourProfile.cs @@ -38,7 +38,7 @@ namespace Emby.Dlna.Profiles { new DirectPlayProfile { - Container = "mp4,mov", + Container = "mp4,mov,m4v", Type = DlnaProfileType.Video, VideoCodec = "h264,mpeg4", AudioCodec = "aac" @@ -201,7 +201,15 @@ namespace Emby.Dlna.Profiles } }; - ResponseProfiles = new ResponseProfile[] { }; + ResponseProfiles = new ResponseProfile[] + { + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" + } + }; } } } diff --git a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs index 5acdde327..c582cb52e 100644 --- a/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs +++ b/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs @@ -43,7 +43,7 @@ namespace Emby.Dlna.Profiles AudioCodec = "ac3", VideoCodec = "h264", Type = DlnaProfileType.Video, - EstimateContentLength = true + EstimateContentLength = false }, new TranscodingProfile { @@ -77,7 +77,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "mp3,aac", Type = DlnaProfileType.Video @@ -335,6 +335,12 @@ namespace Emby.Dlna.Profiles Container = "flac", MimeType = "audio/x-flac", Type = DlnaProfileType.Audio + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; diff --git a/Emby.Dlna/Profiles/SharpSmartTvProfile.cs b/Emby.Dlna/Profiles/SharpSmartTvProfile.cs new file mode 100644 index 000000000..b49ad0197 --- /dev/null +++ b/Emby.Dlna/Profiles/SharpSmartTvProfile.cs @@ -0,0 +1,120 @@ +using System.Xml.Serialization; +using MediaBrowser.Model.Dlna; + +namespace Emby.Dlna.Profiles +{ + [XmlRoot("Profile")] + public class SharpSmartTvProfile : DefaultProfile + { + public SharpSmartTvProfile() + { + Name = "Sharp Smart TV"; + + RequiresPlainFolders = true; + RequiresPlainVideoItems = true; + + Identification = new DeviceIdentification + { + Manufacturer = "Sharp", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "User-Agent", + Value = "Sharp", + Match = HeaderMatchType.Substring + } + } + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new TranscodingProfile + { + Container = "ts", + Type = DlnaProfileType.Video, + AudioCodec = "ac3,aac,mp3,dts,dca", + VideoCodec = "h264", + EnableMpegtsM2TsMode = true + }, + + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "m4v,mkv,avi,mov,mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "aac,mp3,ac3,dts,dca", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "asf,wmv", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mpg,mpeg", + VideoCodec = "mpeg2video", + AudioCodec = "mp3,aac", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "flv", + VideoCodec = "h264", + AudioCodec = "mp3,aac", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mp3,wav", + Type = DlnaProfileType.Audio + } + }; + + SubtitleProfiles = new[] + { + new SubtitleProfile + { + Format = "srt", + Method = SubtitleDeliveryMethod.Embed + }, + new SubtitleProfile + { + Format = "srt", + Method = SubtitleDeliveryMethod.External + } + }; + + ResponseProfiles = new[] + { + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" + } + }; + } + } +} diff --git a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs index d1305d424..c67bd85b2 100644 --- a/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs +++ b/Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs @@ -83,7 +83,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "avi,mp4", + Container = "avi,mp4,m4v", VideoCodec = "mpeg4,h264", AudioCodec = "ac3,aac,mp3,pcm", Type = DlnaProfileType.Video @@ -248,6 +248,13 @@ namespace Emby.Dlna.Profiles Type = DlnaProfileType.Video }, + new ResponseProfile + { + Container = "m4v", + MimeType = "video/mpeg", + Type = DlnaProfileType.Video + }, + new ResponseProfile { Container = "mpeg", diff --git a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs index c21022aa3..427820a33 100644 --- a/Emby.Dlna/Profiles/SonyBravia2011Profile.cs +++ b/Emby.Dlna/Profiles/SonyBravia2011Profile.cs @@ -80,7 +80,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "ac3,aac,mp3", Type = DlnaProfileType.Video @@ -211,6 +211,12 @@ namespace Emby.Dlna.Profiles MimeType = "video/mpeg", OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", Type = DlnaProfileType.Video + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; diff --git a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs index 1bbd40e91..206ca554c 100644 --- a/Emby.Dlna/Profiles/SonyBravia2012Profile.cs +++ b/Emby.Dlna/Profiles/SonyBravia2012Profile.cs @@ -80,7 +80,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "ac3,aac,mp3,mp2", Type = DlnaProfileType.Video @@ -199,6 +199,12 @@ namespace Emby.Dlna.Profiles MimeType = "video/mpeg", OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", Type = DlnaProfileType.Video + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; diff --git a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs index 019bbafcb..c618c9990 100644 --- a/Emby.Dlna/Profiles/SonyBravia2013Profile.cs +++ b/Emby.Dlna/Profiles/SonyBravia2013Profile.cs @@ -79,7 +79,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "ac3,eac3,aac,mp3,mp2", Type = DlnaProfileType.Video @@ -255,6 +255,12 @@ namespace Emby.Dlna.Profiles MimeType = "video/mpeg", OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", Type = DlnaProfileType.Video + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; diff --git a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs index 910786b83..c30bcfc85 100644 --- a/Emby.Dlna/Profiles/SonyBravia2014Profile.cs +++ b/Emby.Dlna/Profiles/SonyBravia2014Profile.cs @@ -79,7 +79,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4", + Container = "mp4,m4v", VideoCodec = "h264,mpeg4", AudioCodec = "ac3,eac3,aac,mp3,mp2", Type = DlnaProfileType.Video @@ -255,6 +255,12 @@ namespace Emby.Dlna.Profiles MimeType = "video/mpeg", OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", Type = DlnaProfileType.Video + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; diff --git a/Emby.Dlna/Profiles/SonyPs4Profile.cs b/Emby.Dlna/Profiles/SonyPs4Profile.cs index 44649911d..832733184 100644 --- a/Emby.Dlna/Profiles/SonyPs4Profile.cs +++ b/Emby.Dlna/Profiles/SonyPs4Profile.cs @@ -63,7 +63,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4,mkv", + Container = "mp4,mkv,m4v", Type = DlnaProfileType.Video, VideoCodec = "h264,mpeg4", AudioCodec = "aac,ac3" @@ -86,7 +86,9 @@ namespace Emby.Dlna.Profiles { Container = "mp3", AudioCodec = "mp3", - Type = DlnaProfileType.Audio + Type = DlnaProfileType.Audio, + // Transcoded audio won't be playable at all without this + TranscodeSeekInfo = TranscodeSeekInfo.Bytes }, new TranscodingProfile { @@ -253,6 +255,13 @@ namespace Emby.Dlna.Profiles Container = "wav", MimeType = "audio/wav", Type = DlnaProfileType.Audio + }, + + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; } diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs index e524816af..6cef2d965 100644 --- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs +++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs @@ -87,7 +87,7 @@ namespace Emby.Dlna.Profiles new DirectPlayProfile { - Container = "mp4,mov", + Container = "mp4,mov,m4v", Type = DlnaProfileType.Video, VideoCodec = "h264,mpeg4", AudioCodec = "ac3,aac,mp2,mp3,dca,dts" diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs index 370534a67..8994082ad 100644 --- a/Emby.Dlna/Profiles/XboxOneProfile.cs +++ b/Emby.Dlna/Profiles/XboxOneProfile.cs @@ -80,7 +80,7 @@ namespace Emby.Dlna.Profiles }, new DirectPlayProfile { - Container = "mp4,mov,mkv", + Container = "mp4,mov,mkv,m4v", VideoCodec = "h264,mpeg4,mpeg2video", AudioCodec = "aac,ac3", Type = DlnaProfileType.Video @@ -349,6 +349,12 @@ namespace Emby.Dlna.Profiles Container = "avi", MimeType = "video/avi", Type = DlnaProfileType.Video + }, + new ResponseProfile + { + Container = "m4v", + Type = DlnaProfileType.Video, + MimeType = "video/mp4" } }; } diff --git a/Emby.Dlna/Profiles/Xml/Default.xml b/Emby.Dlna/Profiles/Xml/Default.xml index 4e29f651b..b5a5d24b6 100644 --- a/Emby.Dlna/Profiles/Xml/Default.xml +++ b/Emby.Dlna/Profiles/Xml/Default.xml @@ -29,8 +29,8 @@ false - - + + diff --git a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml index eb63352a3..556a3d673 100644 --- a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml +++ b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml @@ -5,7 +5,7 @@ Echostar Technologies LLC http://www.echostar.com - + Emby @@ -37,9 +37,7 @@ - - - + diff --git a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml index dc0e97772..2963e5f38 100644 --- a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml +++ b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml @@ -37,7 +37,7 @@ - + @@ -79,7 +79,11 @@ - + + + + + diff --git a/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml b/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml index 862bede9b..c9ea6daff 100644 --- a/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml +++ b/Emby.Dlna/Profiles/Xml/Linksys DMA2100.xml @@ -34,7 +34,7 @@ - + @@ -43,7 +43,11 @@ - + + + + + diff --git a/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml b/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml index d7b142d84..b520b2b53 100644 --- a/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml +++ b/Emby.Dlna/Profiles/Xml/Panasonic Viera.xml @@ -41,7 +41,7 @@ - + @@ -76,6 +76,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml b/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml index 9bc4c2e31..9fa49e94a 100644 --- a/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml +++ b/Emby.Dlna/Profiles/Xml/Popcorn Hour.xml @@ -29,7 +29,7 @@ false - + @@ -81,7 +81,11 @@ - + + + + + diff --git a/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml b/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml index 5b2106da5..a3acea829 100644 --- a/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml +++ b/Emby.Dlna/Profiles/Xml/Samsung Smart TV.xml @@ -40,7 +40,7 @@ - + @@ -51,7 +51,7 @@ - + @@ -117,6 +117,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml b/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml new file mode 100644 index 000000000..e367a8c15 --- /dev/null +++ b/Emby.Dlna/Profiles/Xml/Sharp Smart TV.xml @@ -0,0 +1,60 @@ + + + Sharp Smart TV + + Sharp + + + + + Emby + http://emby.media/ + Emby Server + Emby + Emby + http://emby.media/ + false + false + false + Audio,Photo,Video + JPEG_SM + 480 + 480 + 48 + 48 + 24000000 + 24000000 + 192000 + + DMS-1.50 + http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_50_AC3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=1:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_BASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMA_FULL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000,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:*:video/mpeg:DLNA.ORG_PN=MPEG1;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_KO_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_KO_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-matroska:DLNA.ORG_PN=MATROSKA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AC3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_1080i_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_HP_HD_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_LPCM;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_ASP_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_SP_L6_AAC;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_NDSD;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_ISO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_LPCM_T;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L2_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L3_WMA;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01500000000000000000000000000000 + 0 + true + true + false + false + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml index 154d9a68f..ee113ef63 100644 --- a/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml +++ b/Emby.Dlna/Profiles/Xml/Sony Blu-ray Player.xml @@ -41,7 +41,7 @@ - + @@ -99,6 +99,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml index 39d7674a1..3b234ac36 100644 --- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml +++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2011).xml @@ -41,7 +41,7 @@ - + @@ -129,6 +129,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml index 8b6e88702..4748b8d2a 100644 --- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml +++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2012).xml @@ -41,7 +41,7 @@ - + @@ -105,6 +105,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml index e76ca2c77..d0ec30a26 100644 --- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml +++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2013).xml @@ -41,7 +41,7 @@ - + @@ -104,6 +104,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml index ff4aa9cf8..ba83490b4 100644 --- a/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml +++ b/Emby.Dlna/Profiles/Xml/Sony Bravia (2014).xml @@ -41,7 +41,7 @@ - + @@ -104,6 +104,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml b/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml index 7ec4ccc90..22131a502 100644 --- a/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml +++ b/Emby.Dlna/Profiles/Xml/Sony PlayStation 4.xml @@ -40,12 +40,12 @@ - + - + @@ -98,6 +98,9 @@ + + + diff --git a/Emby.Dlna/Profiles/Xml/WDTV Live.xml b/Emby.Dlna/Profiles/Xml/WDTV Live.xml index 96d37e7fb..1cf3ef597 100644 --- a/Emby.Dlna/Profiles/Xml/WDTV Live.xml +++ b/Emby.Dlna/Profiles/Xml/WDTV Live.xml @@ -40,7 +40,7 @@ - + diff --git a/Emby.Dlna/Profiles/Xml/Xbox One.xml b/Emby.Dlna/Profiles/Xml/Xbox One.xml index 8c13ed8fd..6289847ca 100644 --- a/Emby.Dlna/Profiles/Xml/Xbox One.xml +++ b/Emby.Dlna/Profiles/Xml/Xbox One.xml @@ -39,7 +39,7 @@ - + @@ -116,6 +116,9 @@ + + + diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs index 1cd19d010..3f0e070ca 100644 --- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs +++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs @@ -104,7 +104,8 @@ namespace Emby.Dlna.Ssdp Argument = new UpnpDeviceInfo { Location = e.DiscoveredDevice.DescriptionLocation, - Headers = headers + Headers = headers, + LocalIpAddress = e.LocalIpAddress } }; diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 215ac8492..b9412d0fb 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -326,6 +326,8 @@ namespace Emby.Server.Core } } + public abstract bool IsRunningAsService { get; } + private Assembly GetAssembly(Type type) { return type.GetTypeInfo().Assembly; @@ -489,7 +491,8 @@ namespace Emby.Server.Core { var migrations = new List { - new LibraryScanMigration(ServerConfigurationManager, TaskManager) + new LibraryScanMigration(ServerConfigurationManager, TaskManager), + new GuideMigration(ServerConfigurationManager, TaskManager) }; foreach (var task in migrations) @@ -1247,7 +1250,6 @@ namespace Emby.Server.Core HasUpdateAvailable = HasUpdateAvailable, SupportsAutoRunAtStartup = SupportsAutoRunAtStartup, TranscodingTempPath = ApplicationPaths.TranscodingTempPath, - IsRunningAsService = IsRunningAsService, SupportsRunningAsService = SupportsRunningAsService, ServerName = FriendlyName, LocalAddress = localAddress, @@ -1476,6 +1478,10 @@ namespace Emby.Server.Core try { AuthorizeServer(); + } + catch (NotImplementedException) + { + } catch (Exception ex) { diff --git a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs index b75de2ff4..eb3a71465 100644 --- a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs @@ -11,6 +11,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Threading; using Mono.Nat; +using System.Threading.Tasks; namespace Emby.Server.Core.EntryPoints { @@ -106,6 +107,11 @@ namespace Emby.Server.Core.EntryPoints private async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs e) { + if (_disposed) + { + return; + } + var info = e.Argument; string usn; @@ -169,6 +175,11 @@ namespace Emby.Server.Core.EntryPoints return; } + if (_disposed) + { + return; + } + _logger.Debug("Calling Nat.Handle on " + identifier); NatUtility.Handle(localAddress, info, endpoint, NatProtocol.Upnp); } @@ -185,6 +196,11 @@ namespace Emby.Server.Core.EntryPoints void NatUtility_DeviceFound(object sender, DeviceEventArgs e) { + if (_disposed) + { + return; + } + try { var device = e.Device; @@ -208,8 +224,13 @@ namespace Emby.Server.Core.EntryPoints private List _createdRules = new List(); private List _usnsHandled = new List(); - private void CreateRules(INatDevice device) + private async void CreateRules(INatDevice device) { + if (_disposed) + { + throw new ObjectDisposedException("PortMapper"); + } + // On some systems the device discovered event seems to fire repeatedly // This check will help ensure we're not trying to port map the same device over and over @@ -219,12 +240,16 @@ namespace Emby.Server.Core.EntryPoints { _createdRules.Add(address); - CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort); - CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort); + var success = await CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort).ConfigureAwait(false); + + if (success) + { + await CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort).ConfigureAwait(false); + } } } - private async void CreatePortMap(INatDevice device, int privatePort, int publicPort) + private async Task CreatePortMap(INatDevice device, int privatePort, int publicPort) { _logger.Debug("Creating port map on port {0}", privatePort); @@ -235,10 +260,14 @@ namespace Emby.Server.Core.EntryPoints Description = _appHost.Name }).ConfigureAwait(false); + + return true; } catch (Exception ex) { _logger.Error("Error creating port map: " + ex.Message); + + return false; } } @@ -249,8 +278,10 @@ namespace Emby.Server.Core.EntryPoints _logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString()); } + private bool _disposed = false; public void Dispose() { + _disposed = true; DisposeNat(); } diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Core/IO/LibraryMonitor.cs index 6ed096f44..f0ecb9d89 100644 --- a/Emby.Server.Core/IO/LibraryMonitor.cs +++ b/Emby.Server.Core/IO/LibraryMonitor.cs @@ -87,7 +87,7 @@ namespace Emby.Server.Core.IO public bool IsPathLocked(string path) { var lockedPaths = _tempIgnoredPaths.Keys.ToList(); - return lockedPaths.Any(i => string.Equals(i, path, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(i, path)); + return lockedPaths.Any(i => _fileSystem.AreEqual(i, path) || _fileSystem.ContainsSubPath(i, path)); } public async void ReportFileSystemChangeComplete(string path, bool refreshPath) @@ -288,6 +288,13 @@ namespace Emby.Server.Core.IO { try { + if (!_fileSystem.DirectoryExists(path)) + { + // Seeing a crash in the mono runtime due to an exception being thrown on a different thread + Logger.Info("Skipping realtime monitor for {0} because the path does not exist", path); + return; + } + var newWatcher = new FileSystemWatcher(path, "*") { IncludeSubdirectories = true diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 11fd3a872..d3b2ef7ef 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -138,7 +138,7 @@ namespace Emby.Server.Implementations.Activity CreateLogEntry(new ActivityLogEntry { - Name = string.Format(_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), user.Name, item.Name), + Name = string.Format(_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), user.Name, Notifications.Notifications.GetItemName(item)), Type = "PlaybackStopped", ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), e.ClientName, e.DeviceName), UserId = user.Id.ToString("N") @@ -170,7 +170,7 @@ namespace Emby.Server.Implementations.Activity CreateLogEntry(new ActivityLogEntry { - Name = string.Format(_localization.GetLocalizedString("UserStartedPlayingItemWithValues"), user.Name, item.Name), + Name = string.Format(_localization.GetLocalizedString("UserStartedPlayingItemWithValues"), user.Name, Notifications.Notifications.GetItemName(item)), Type = "PlaybackStart", ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), e.ClientName, e.DeviceName), UserId = user.Id.ToString("N") @@ -235,10 +235,6 @@ namespace Emby.Server.Implementations.Activity }); } - void _logManager_LoggerLoaded(object sender, EventArgs e) - { - } - void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) { CreateLogEntry(new ActivityLogEntry diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index f7dc93009..8f03fa7a4 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -343,7 +343,7 @@ namespace Emby.Server.Implementations.Channels private MediaSourceInfo GetMediaSource(BaseItem item, ChannelMediaInfo info) { - var source = info.ToMediaSource(); + var source = info.ToMediaSource(item.Id); source.RunTimeTicks = source.RunTimeTicks ?? item.RunTimeTicks; diff --git a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs b/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs index 170ef07f3..b5639773b 100644 --- a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs +++ b/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -9,6 +9,7 @@ using System; using System.IO; using System.Text; using System.Threading.Tasks; +using MediaBrowser.Controller.Security; using MediaBrowser.Model.IO; using MediaBrowser.Model.Threading; @@ -17,6 +18,7 @@ namespace Emby.Server.Implementations.Connect public class ConnectEntryPoint : IServerEntryPoint { private ITimer _timer; + private IpAddressInfo _cachedIpAddress; private readonly IHttpClient _httpClient; private readonly IApplicationPaths _appPaths; private readonly ILogger _logger; @@ -26,8 +28,9 @@ namespace Emby.Server.Implementations.Connect private readonly IApplicationHost _appHost; private readonly IFileSystem _fileSystem; private readonly ITimerFactory _timerFactory; + private readonly IEncryptionManager _encryption; - public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem, ITimerFactory timerFactory) + public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem, ITimerFactory timerFactory, IEncryptionManager encryption) { _httpClient = httpClient; _appPaths = appPaths; @@ -37,6 +40,7 @@ namespace Emby.Server.Implementations.Connect _appHost = appHost; _fileSystem = fileSystem; _timerFactory = timerFactory; + _encryption = encryption; } public void Run() @@ -143,17 +147,31 @@ namespace Emby.Server.Implementations.Connect private string CacheFilePath { - get { return Path.Combine(_appPaths.DataPath, "wan.txt"); } + get { return Path.Combine(_appPaths.DataPath, "wan.dat"); } } private void CacheAddress(IpAddressInfo address) { + if (_cachedIpAddress != null && _cachedIpAddress.Equals(address)) + { + // no need to update the file if the address has not changed + return; + } + var path = CacheFilePath; try { _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); - _fileSystem.WriteAllText(path, address.ToString(), Encoding.UTF8); + } + catch (Exception ex) + { + } + + try + { + _fileSystem.WriteAllText(path, _encryption.EncryptString(address.ToString()), Encoding.UTF8); + _cachedIpAddress = address; } catch (Exception ex) { @@ -169,11 +187,12 @@ namespace Emby.Server.Implementations.Connect try { - var endpoint = _fileSystem.ReadAllText(path, Encoding.UTF8); + var endpoint = _encryption.DecryptString(_fileSystem.ReadAllText(path, Encoding.UTF8)); IpAddressInfo ipAddress; if (_networkManager.TryParseIpAddress(endpoint, out ipAddress)) { + _cachedIpAddress = ipAddress; ((ConnectManager)_connectManager).OnWanAddressResolved(ipAddress); } } diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs index 8c8b7b026..7e6755f6a 100644 --- a/Emby.Server.Implementations/Connect/ConnectManager.cs +++ b/Emby.Server.Implementations/Connect/ConnectManager.cs @@ -925,7 +925,11 @@ namespace Emby.Server.Implementations.Connect } _data.PendingAuthorizations = newPendingList; - CacheData(); + + if (!newPendingList.Select(i => i.Id).SequenceEqual(currentPendingList.Select(i => i.Id), StringComparer.Ordinal)) + { + CacheData(); + } await RefreshGuestNames(list, refreshImages).ConfigureAwait(false); } @@ -1118,7 +1122,7 @@ namespace Emby.Server.Implementations.Connect } } - public async Task Authenticate(string username, string passwordMd5) + public async Task Authenticate(string username, string passwordMd5) { if (string.IsNullOrWhiteSpace(username)) { @@ -1147,6 +1151,7 @@ namespace Emby.Server.Implementations.Connect // No need to examine the response using (var response = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) { + return _json.DeserializeFromStream(response); } } diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs index 5bc3a625f..2819a249f 100644 --- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs +++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs @@ -137,6 +137,11 @@ namespace Emby.Server.Implementations.Data var numComplete = 0; var numItems = result.Count; + var allLibraryPaths = _libraryManager + .GetVirtualFolders() + .SelectMany(i => i.Locations) + .ToList(); + foreach (var item in result) { cancellationToken.ThrowIfCancellationRequested(); @@ -170,9 +175,8 @@ namespace Emby.Server.Implementations.Data continue; } - if (Folder.IsPathOffline(path)) + if (Folder.IsPathOffline(path, allLibraryPaths)) { - await libraryItem.UpdateIsOffline(true).ConfigureAwait(false); continue; } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 8c16216b9..c158f2e51 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -372,7 +372,7 @@ namespace Emby.Server.Implementations.Data userDataRepo.Initialize(WriteLock, _connection); - _shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(15)); + _shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(30)); } private void OnShrinkMemoryTimerCallback(object state) @@ -2384,8 +2384,17 @@ namespace Emby.Server.Implementations.Data var excludeIds = query.ExcludeItemIds.ToList(); excludeIds.Add(item.Id.ToString("N")); - query.ExcludeItemIds = excludeIds.ToArray(); + if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name)) + { + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + excludeIds.AddRange(hasTrailers.GetTrailerIds().Select(i => i.ToString("N"))); + } + } + + query.ExcludeItemIds = excludeIds.ToArray(); query.ExcludeProviderIds = item.ProviderIds; } @@ -2548,57 +2557,53 @@ namespace Emby.Server.Implementations.Data { using (var connection = CreateConnection(true)) { - return connection.RunInTransaction(db => + var list = new List(); + + using (var statement = PrepareStatementSafe(connection, commandText)) { - var list = new List(); - - using (var statement = PrepareStatementSafe(db, commandText)) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) + statement.TryBind("@UserId", query.User.Id); + } + + BindSimilarParams(query, statement); + + // Running this again will bind the params + GetWhereClauses(query, statement); + + foreach (var row in statement.ExecuteQuery()) + { + var item = GetItem(row, query); + if (item != null) { - statement.TryBind("@UserId", query.User.Id); + list.Add(item); } + } + } - BindSimilarParams(query, statement); + // Hack for right now since we currently don't support filtering out these duplicates within a query + if (query.EnableGroupByMetadataKey) + { + var limit = query.Limit ?? int.MaxValue; + limit -= 4; + var newList = new List(); - // Running this again will bind the params - GetWhereClauses(query, statement); + foreach (var item in list) + { + AddItem(newList, item); - foreach (var row in statement.ExecuteQuery()) + if (newList.Count >= limit) { - var item = GetItem(row, query); - if (item != null) - { - list.Add(item); - } + break; } } - // Hack for right now since we currently don't support filtering out these duplicates within a query - if (query.EnableGroupByMetadataKey) - { - var limit = query.Limit ?? int.MaxValue; - limit -= 4; - var newList = new List(); + list = newList; + } - foreach (var item in list) - { - AddItem(newList, item); + LogQueryTime("GetItemList", commandText, now); - if (newList.Count >= limit) - { - break; - } - } - - list = newList; - } - - LogQueryTime("GetItemList", commandText, now); - - return list; - - }, ReadTransactionMode); + return list; } } } @@ -2652,7 +2657,7 @@ namespace Emby.Server.Implementations.Data { //Logger.Debug("{2} query time: {0}ms. Query: {1}", // Convert.ToInt32(elapsed), - // cmd.CommandText, + // commandText, // methodName); } } @@ -2825,8 +2830,9 @@ namespace Emby.Server.Implementations.Data { if (orderBy.Count == 0) { - orderBy.Add(new Tuple("SimilarityScore", SortOrder.Descending)); orderBy.Add(new Tuple(ItemSortBy.Random, SortOrder.Ascending)); + orderBy.Add(new Tuple("SimilarityScore", SortOrder.Descending)); + //orderBy.Add(new Tuple(ItemSortBy.Random, SortOrder.Ascending)); query.SortOrder = SortOrder.Descending; enableOrderInversion = false; } @@ -3212,6 +3218,11 @@ namespace Emby.Server.Implementations.Data private List GetWhereClauses(InternalItemsQuery query, IStatement statement, string paramSuffix = "") { + if (query.IsResumable ?? false) + { + query.IsVirtualItem = false; + } + var whereClauses = new List(); if (EnableJoinUserData(query)) @@ -3372,9 +3383,9 @@ namespace Emby.Server.Implementations.Data } } - if (query.SimilarTo != null) + if (query.SimilarTo != null && query.MinSimilarityScore > 0) { - whereClauses.Add("SimilarityScore > 0"); + whereClauses.Add("SimilarityScore > " + (query.MinSimilarityScore - 1).ToString(CultureInfo.InvariantCulture)); } if (query.IsFolder.HasValue) @@ -3616,10 +3627,12 @@ namespace Emby.Server.Implementations.Data var index = 0; foreach (var type in query.TrailerTypes) { - clauses.Add("TrailerTypes like @TrailerTypes" + index); + var paramName = "@TrailerTypes" + index; + + clauses.Add("TrailerTypes like " + paramName); if (statement != null) { - statement.TryBind("@TrailerTypes" + index, "%" + type + "%"); + statement.TryBind(paramName, "%" + type + "%"); } index++; } @@ -4085,27 +4098,6 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("LocationType in (" + val + ")"); } - if (query.ExcludeLocationTypes.Length == 1) - { - if (query.ExcludeLocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90) - { - query.IsVirtualItem = false; - } - else - { - whereClauses.Add("LocationType<>@ExcludeLocationTypes"); - if (statement != null) - { - statement.TryBind("@ExcludeLocationTypes", query.ExcludeLocationTypes[0].ToString()); - } - } - } - else if (query.ExcludeLocationTypes.Length > 1) - { - var val = string.Join(",", query.ExcludeLocationTypes.Select(i => "'" + i + "'").ToArray()); - - whereClauses.Add("LocationType not in (" + val + ")"); - } if (query.IsVirtualItem.HasValue) { whereClauses.Add("IsVirtualItem=@IsVirtualItem"); @@ -4221,7 +4213,7 @@ namespace Emby.Server.Implementations.Data var paramName = "@ExcludeProviderId" + index; //excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")"); - excludeIds.Add("ProviderIds not like " + paramName); + excludeIds.Add("(ProviderIds is null or ProviderIds not like " + paramName + ")"); if (statement != null) { statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%"); diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 8e6c1263d..f866c34de 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -361,10 +361,7 @@ namespace Emby.Server.Implementations.Dto if (collectionFolder != null) { dto.OriginalCollectionType = collectionFolder.CollectionType; - - dto.CollectionType = user == null ? - collectionFolder.CollectionType : - collectionFolder.GetViewType(user); + dto.CollectionType = collectionFolder.CollectionType; } if (fields.Contains(ItemFields.CanDelete)) @@ -1515,7 +1512,8 @@ namespace Emby.Server.Implementations.Dto return artist; } } - return item.GetParent(); + + return item.DisplayParent ?? item.GetParent(); } private void AddInheritedImages(BaseItemDto dto, BaseItem item, DtoOptions options, BaseItem owner) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 7ee0c566f..e3cd96894 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -182,6 +182,7 @@ + diff --git a/Emby.Server.Implementations/EntryPoints/SystemEvents.cs b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs index 021ae47ec..4ab6d32f3 100644 --- a/Emby.Server.Implementations/EntryPoints/SystemEvents.cs +++ b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs @@ -6,15 +6,16 @@ using System.Threading.Tasks; using MediaBrowser.Model.System; using MediaBrowser.Controller.Plugins; using MediaBrowser.Common; +using MediaBrowser.Controller; namespace Emby.Server.Implementations.EntryPoints { public class SystemEvents : IServerEntryPoint { private readonly ISystemEvents _systemEvents; - private readonly IApplicationHost _appHost; + private readonly IServerApplicationHost _appHost; - public SystemEvents(ISystemEvents systemEvents, IApplicationHost appHost) + public SystemEvents(ISystemEvents systemEvents, IServerApplicationHost appHost) { _systemEvents = systemEvents; _appHost = appHost; diff --git a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs index 1b897ca29..9fbe06673 100644 --- a/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs @@ -10,6 +10,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; namespace Emby.Server.Implementations.EntryPoints @@ -19,7 +20,7 @@ namespace Emby.Server.Implementations.EntryPoints /// public class UsageEntryPoint : IServerEntryPoint { - private readonly IApplicationHost _applicationHost; + private readonly IServerApplicationHost _applicationHost; private readonly IHttpClient _httpClient; private readonly ILogger _logger; private readonly ISessionManager _sessionManager; @@ -28,7 +29,7 @@ namespace Emby.Server.Implementations.EntryPoints private readonly ConcurrentDictionary _apps = new ConcurrentDictionary(); - public UsageEntryPoint(ILogger logger, IApplicationHost applicationHost, IHttpClient httpClient, ISessionManager sessionManager, IUserManager userManager, IServerConfigurationManager config) + public UsageEntryPoint(ILogger logger, IServerApplicationHost applicationHost, IHttpClient httpClient, ISessionManager sessionManager, IUserManager userManager, IServerConfigurationManager config) { _logger = logger; _applicationHost = applicationHost; diff --git a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs index be848acb7..31254c6c2 100644 --- a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs +++ b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs @@ -8,19 +8,20 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller; using MediaBrowser.Model.Logging; namespace Emby.Server.Implementations.EntryPoints { public class UsageReporter { - private readonly IApplicationHost _applicationHost; + private readonly IServerApplicationHost _applicationHost; private readonly IHttpClient _httpClient; private readonly IUserManager _userManager; private readonly ILogger _logger; private const string MbAdminUrl = "https://www.mb3admin.com/admin/"; - public UsageReporter(IApplicationHost applicationHost, IHttpClient httpClient, IUserManager userManager, ILogger logger) + public UsageReporter(IServerApplicationHost applicationHost, IHttpClient httpClient, IUserManager userManager, ILogger logger) { _applicationHost = applicationHost; _httpClient = httpClient; diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 5bb21d02a..f841b8b6b 100644 --- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -61,92 +61,92 @@ namespace Emby.Server.Implementations.FileOrganization }; try - { - if (_libraryMonitor.IsPathLocked(path)) { - result.Status = FileSortingStatus.Failure; - result.StatusMessage = "Path is locked by other processes. Please try again later."; - return result; - } - - var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); - var resolver = new EpisodeResolver(namingOptions, new NullLogger()); - - var episodeInfo = resolver.Resolve(path, false) ?? - new MediaBrowser.Naming.TV.EpisodeInfo(); - - var seriesName = episodeInfo.SeriesName; - - if (!string.IsNullOrEmpty(seriesName)) - { - var seasonNumber = episodeInfo.SeasonNumber; - - result.ExtractedSeasonNumber = seasonNumber; - - // Passing in true will include a few extra regex's - var episodeNumber = episodeInfo.EpisodeNumber; - - result.ExtractedEpisodeNumber = episodeNumber; - - var premiereDate = episodeInfo.IsByDate ? - new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) : - (DateTime?)null; - - if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue)) + if (_libraryMonitor.IsPathLocked(path)) { - if (episodeInfo.IsByDate) + result.Status = FileSortingStatus.Failure; + result.StatusMessage = "Path is locked by other processes. Please try again later."; + return result; + } + + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); + var resolver = new EpisodeResolver(namingOptions, new NullLogger()); + + var episodeInfo = resolver.Resolve(path, false) ?? + new MediaBrowser.Naming.TV.EpisodeInfo(); + + var seriesName = episodeInfo.SeriesName; + + if (!string.IsNullOrEmpty(seriesName)) + { + var seasonNumber = episodeInfo.SeasonNumber; + + result.ExtractedSeasonNumber = seasonNumber; + + // Passing in true will include a few extra regex's + var episodeNumber = episodeInfo.EpisodeNumber; + + result.ExtractedEpisodeNumber = episodeNumber; + + var premiereDate = episodeInfo.IsByDate ? + new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) : + (DateTime?)null; + + if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue)) { - _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value); + if (episodeInfo.IsByDate) + { + _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value); + } + else + { + _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber); + } + + var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber; + + result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; + + await OrganizeEpisode(path, + seriesName, + seasonNumber, + episodeNumber, + endingEpisodeNumber, + premiereDate, + options, + overwriteExisting, + false, + result, + cancellationToken).ConfigureAwait(false); } else { - _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber); + var msg = string.Format("Unable to determine episode number from {0}", path); + result.Status = FileSortingStatus.Failure; + result.StatusMessage = msg; + _logger.Warn(msg); } - - var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber; - - result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; - - await OrganizeEpisode(path, - seriesName, - seasonNumber, - episodeNumber, - endingEpisodeNumber, - premiereDate, - options, - overwriteExisting, - false, - result, - cancellationToken).ConfigureAwait(false); } else { - var msg = string.Format("Unable to determine episode number from {0}", path); + var msg = string.Format("Unable to determine series name from {0}", path); result.Status = FileSortingStatus.Failure; result.StatusMessage = msg; _logger.Warn(msg); } - } - else - { - var msg = string.Format("Unable to determine series name from {0}", path); - result.Status = FileSortingStatus.Failure; - result.StatusMessage = msg; - _logger.Warn(msg); - } - var previousResult = _organizationService.GetResultBySourcePath(path); + var previousResult = _organizationService.GetResultBySourcePath(path); - if (previousResult != null) - { - // Don't keep saving the same result over and over if nothing has changed - if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success) + if (previousResult != null) { - return previousResult; + // Don't keep saving the same result over and over if nothing has changed + if (previousResult.Status == result.Status && previousResult.StatusMessage == result.StatusMessage && result.Status != FileSortingStatus.Success) + { + return previousResult; + } } - } - await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); + await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -162,58 +162,60 @@ namespace Emby.Server.Implementations.FileOrganization var result = _organizationService.GetResult(request.ResultId); try - { - Series series = null; - - if (request.NewSeriesProviderIds.Count > 0) { - // We're having a new series here - SeriesInfo seriesRequest = new SeriesInfo(); - seriesRequest.ProviderIds = request.NewSeriesProviderIds; + Series series = null; - var refreshOptions = new MetadataRefreshOptions(_fileSystem); - series = new Series(); - series.Id = Guid.NewGuid(); - series.Name = request.NewSeriesName; - - int year; - if (int.TryParse(request.NewSeriesYear, out year)) + if (request.NewSeriesProviderIds.Count > 0) { - series.ProductionYear = year; + // We're having a new series here + SeriesInfo seriesRequest = new SeriesInfo(); + seriesRequest.ProviderIds = request.NewSeriesProviderIds; + + var refreshOptions = new MetadataRefreshOptions(_fileSystem); + series = new Series(); + series.Id = Guid.NewGuid(); + series.Name = request.NewSeriesName; + + int year; + if (int.TryParse(request.NewSeriesYear, out year)) + { + series.ProductionYear = year; + } + + var seriesFolderName = series.Name; + if (series.ProductionYear.HasValue) + { + seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear); + } + + seriesFolderName = _fileSystem.GetValidFilename(seriesFolderName); + + series.Path = Path.Combine(request.TargetFolder, seriesFolderName); + + series.ProviderIds = request.NewSeriesProviderIds; + + await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); } - var seriesFolderName = series.Name; - if (series.ProductionYear.HasValue) + if (series == null) { - seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear); + // Existing Series + series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId)); } - series.Path = Path.Combine(request.TargetFolder, seriesFolderName); + await OrganizeEpisode(result.OriginalPath, + series, + request.SeasonNumber, + request.EpisodeNumber, + request.EndingEpisodeNumber, + null, + options, + true, + request.RememberCorrection, + result, + cancellationToken).ConfigureAwait(false); - series.ProviderIds = request.NewSeriesProviderIds; - - await series.RefreshMetadata(refreshOptions, cancellationToken); - } - - if (series == null) - { - // Existing Series - series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId)); - } - - await OrganizeEpisode(result.OriginalPath, - series, - request.SeasonNumber, - request.EpisodeNumber, - request.EndingEpisodeNumber, - null, - options, - true, - request.RememberCorrection, - result, - cancellationToken).ConfigureAwait(false); - - await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); + await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { @@ -287,91 +289,91 @@ namespace Emby.Server.Implementations.FileOrganization { throw new Exception("File is currently processed otherwise. Please try again later."); } - + try { - // Proceed to sort the file - var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false); + // Proceed to sort the file + var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options.TvOptions, cancellationToken).ConfigureAwait(false); - if (string.IsNullOrEmpty(newPath)) - { - var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath); - throw new Exception(msg); - } - - _logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath); - result.TargetPath = newPath; - - var fileExists = _fileSystem.FileExists(result.TargetPath); - var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber); - - if (!overwriteExisting) - { - if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath)) + if (string.IsNullOrEmpty(newPath)) { - var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath); - _logger.Info(msg); - result.Status = FileSortingStatus.SkippedExisting; - result.StatusMessage = msg; - return; + var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath); + throw new Exception(msg); } - if (fileExists) + _logger.Info("Sorting file {0} to new path {1}", sourcePath, newPath); + result.TargetPath = newPath; + + var fileExists = _fileSystem.FileExists(result.TargetPath); + var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber); + + if (!overwriteExisting) { - var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath); - _logger.Info(msg); - result.Status = FileSortingStatus.SkippedExisting; - result.StatusMessage = msg; - result.TargetPath = newPath; - return; + if (options.TvOptions.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath)) + { + var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath); + _logger.Info(msg); + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = msg; + return; + } + + if (fileExists) + { + var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath); + _logger.Info(msg); + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = msg; + result.TargetPath = newPath; + return; + } + + if (otherDuplicatePaths.Count > 0) + { + var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths)); + _logger.Info(msg); + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = msg; + result.DuplicatePaths = otherDuplicatePaths; + return; + } } - if (otherDuplicatePaths.Count > 0) + PerformFileSorting(options.TvOptions, result); + + if (overwriteExisting) { - var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths)); - _logger.Info(msg); - result.Status = FileSortingStatus.SkippedExisting; - result.StatusMessage = msg; - result.DuplicatePaths = otherDuplicatePaths; - return; - } - } + var hasRenamedFiles = false; - PerformFileSorting(options.TvOptions, result); - - if (overwriteExisting) - { - var hasRenamedFiles = false; - - foreach (var path in otherDuplicatePaths) - { - _logger.Debug("Removing duplicate episode {0}", path); - - _libraryMonitor.ReportFileSystemChangeBeginning(path); - - var renameRelatedFiles = !hasRenamedFiles && - string.Equals(Path.GetDirectoryName(path), Path.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase); - - if (renameRelatedFiles) + foreach (var path in otherDuplicatePaths) { - hasRenamedFiles = true; - } + _logger.Debug("Removing duplicate episode {0}", path); - try - { - DeleteLibraryFile(path, renameRelatedFiles, result.TargetPath); - } - catch (IOException ex) - { - _logger.ErrorException("Error removing duplicate episode", ex, path); - } - finally - { - _libraryMonitor.ReportFileSystemChangeComplete(path, true); + _libraryMonitor.ReportFileSystemChangeBeginning(path); + + var renameRelatedFiles = !hasRenamedFiles && + string.Equals(Path.GetDirectoryName(path), Path.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase); + + if (renameRelatedFiles) + { + hasRenamedFiles = true; + } + + try + { + DeleteLibraryFile(path, renameRelatedFiles, result.TargetPath); + } + catch (IOException ex) + { + _logger.ErrorException("Error removing duplicate episode", ex, path); + } + finally + { + _libraryMonitor.ReportFileSystemChangeComplete(path, true); + } } } } - } catch (Exception ex) { result.Status = FileSortingStatus.Failure; diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index ec3dfeb60..ede85fb67 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -49,6 +49,7 @@ namespace Emby.Server.Implementations.HttpServer.Security string device = null; string client = null; string version = null; + string token = null; if (auth != null) { @@ -56,9 +57,13 @@ namespace Emby.Server.Implementations.HttpServer.Security auth.TryGetValue("Device", out device); auth.TryGetValue("Client", out client); auth.TryGetValue("Version", out version); + auth.TryGetValue("Token", out token); } - var token = httpReq.Headers["X-Emby-Token"]; + if (string.IsNullOrWhiteSpace(token)) + { + token = httpReq.Headers["X-Emby-Token"]; + } if (string.IsNullOrWhiteSpace(token)) { @@ -156,8 +161,10 @@ namespace Emby.Server.Implementations.HttpServer.Security // There should be at least to parts if (parts.Length != 2) return null; + var acceptedNames = new[] { "MediaBrowser", "Emby"}; + // It has to be a digest request - if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) + if (!acceptedNames.Contains(parts[0] ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { return null; } @@ -174,7 +181,7 @@ namespace Emby.Server.Implementations.HttpServer.Security if (param.Length == 2) { - var value = NormalizeValue (param[1].Trim(new[] { '"' })); + var value = NormalizeValue(param[1].Trim(new[] { '"' })); result.Add(param[0], value); } } @@ -182,14 +189,14 @@ namespace Emby.Server.Implementations.HttpServer.Security return result; } - private string NormalizeValue(string value) - { - if (string.IsNullOrWhiteSpace (value)) - { - return value; - } + private string NormalizeValue(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return value; + } - return System.Net.WebUtility.HtmlEncode(value); - } + return System.Net.WebUtility.HtmlEncode(value); + } } } diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 39033249f..d7f2ffa43 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -261,10 +261,11 @@ namespace Emby.Server.Implementations.IO // In order to determine if the file is being written to, we have to request write access // But if the server only has readonly access, this is going to cause this entire algorithm to fail // So we'll take a best guess about our access level - var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta - ? FileAccessMode.ReadWrite - : FileAccessMode.Read; + //var requestedFileAccess = ConfigurationManager.Configuration.SaveLocalMeta + // ? FileAccessMode.ReadWrite + // : FileAccessMode.Read; + var requestedFileAccess = FileAccessMode.Read; try { using (_fileSystem.GetFileStream(path, FileOpenMode.Open, requestedFileAccess, FileShareMode.ReadWrite)) diff --git a/Emby.Server.Implementations/Intros/DefaultIntroProvider.cs b/Emby.Server.Implementations/Intros/DefaultIntroProvider.cs index 180f6aba7..4d19a0e9b 100644 --- a/Emby.Server.Implementations/Intros/DefaultIntroProvider.cs +++ b/Emby.Server.Implementations/Intros/DefaultIntroProvider.cs @@ -100,20 +100,30 @@ namespace Emby.Server.Implementations.Intros if (trailerTypes.Count > 0) { + if (trailerTypes.Count >= 5) + { + trailerTypes.Clear(); + } + + // hack - can't filter by user library because local trailers get TopParentId =null in the db. + // for now we have to use a post-query filter afterwards to solve that var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Trailer).Name }, TrailerTypes = trailerTypes.ToArray(), SimilarTo = item, - IsPlayed = config.EnableIntrosForWatchedContent ? (bool?)null : false, + //IsPlayed = config.EnableIntrosForWatchedContent ? (bool?)null : false, MaxParentalRating = config.EnableIntrosParentalControl ? ratingLevel : null, BlockUnratedItems = config.EnableIntrosParentalControl ? new[] { UnratedItem.Trailer } : new UnratedItem[] { }, // Account for duplicates by imdb id, since the database doesn't support this yet - Limit = config.TrailerLimit * 2, + Limit = config.TrailerLimit * 4, SourceTypes = sourceTypes.ToArray() - - }).Where(i => string.IsNullOrWhiteSpace(i.GetProviderId(MetadataProviders.Imdb)) || !string.Equals(i.GetProviderId(MetadataProviders.Imdb), item.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)).Take(config.TrailerLimit); + }) + .Where(i => string.IsNullOrWhiteSpace(i.GetProviderId(MetadataProviders.Imdb)) || !string.Equals(i.GetProviderId(MetadataProviders.Imdb), item.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase)) + .Where(i => i.IsVisibleStandalone(user)) + .Where(i => config.EnableIntrosForWatchedContent || !i.IsPlayed(user)) + .Take(config.TrailerLimit); candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 4c788a2ab..c59a22884 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1956,30 +1956,6 @@ namespace Emby.Server.Implementations.Library var options = collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions(); - if (options.SchemaVersion < 3) - { - options.SaveLocalMetadata = ConfigurationManager.Configuration.SaveLocalMeta; - options.EnableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders; - } - - if (options.SchemaVersion < 2) - { - var chapterOptions = ConfigurationManager.GetConfiguration("chapters"); - options.ExtractChapterImagesDuringLibraryScan = chapterOptions.ExtractDuringLibraryScan; - - if (collectionFolder != null) - { - if (string.Equals(collectionFolder.CollectionType, "movies", StringComparison.OrdinalIgnoreCase)) - { - options.EnableChapterImageExtraction = chapterOptions.EnableMovieChapterImageExtraction; - } - else if (string.Equals(collectionFolder.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) - { - options.EnableChapterImageExtraction = chapterOptions.EnableEpisodeChapterImageExtraction; - } - } - } - return options; } @@ -2034,7 +2010,7 @@ namespace Emby.Server.Implementations.Library private string GetContentTypeOverride(string path, bool inherit) { - var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path))); + var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path))); if (nameValuePair != null) { return nameValuePair.Value; @@ -2505,6 +2481,8 @@ namespace Emby.Server.Implementations.Library options.VideoFileExtensions.Remove(".zip"); } + options.VideoFileExtensions.Add(".tp"); + return options; } @@ -2615,7 +2593,7 @@ namespace Emby.Server.Implementations.Library { foreach (var pathInfo in libraryOptions.PathInfos) { - if (string.IsNullOrWhiteSpace(pathInfo.NetworkPath)) + if (string.IsNullOrWhiteSpace(pathInfo.Path) || string.IsNullOrWhiteSpace(pathInfo.NetworkPath)) { continue; } @@ -2643,10 +2621,13 @@ namespace Emby.Server.Implementations.Library foreach (var map in ConfigurationManager.Configuration.PathSubstitutions) { - var substitutionResult = SubstitutePathInternal(path, map.From, map.To); - if (substitutionResult.Item2) + if (!string.IsNullOrWhiteSpace(map.From)) { - return substitutionResult.Item1; + var substitutionResult = SubstitutePathInternal(path, map.From, map.To); + if (substitutionResult.Item2) + { + return substitutionResult.Item1; + } } } @@ -3088,7 +3069,7 @@ namespace Emby.Server.Implementations.Library { removeList.Add(contentType); } - else if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase) + else if (_fileSystem.AreEqual(path, contentType.Name) || _fileSystem.ContainsSubPath(path, contentType.Name)) { removeList.Add(contentType); diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 93c406ebc..c1bd8fe91 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -199,6 +199,8 @@ namespace Emby.Server.Implementations.Library foreach (var mediaSource in list) { + mediaSource.InferTotalBitrate(); + SetKeyProperties(provider, mediaSource); } diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 7669dd0bf..9d07837c6 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -105,11 +105,10 @@ namespace Emby.Server.Implementations.Library return inputItems .Cast