diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 7db282dc86..5d6ef1adfe 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -491,18 +491,27 @@ private QueryResult GetUserItems(BaseItem item, StubType? stubType, return GetGenreItems(item, null, user, sort, startIndex, limit); } - var collectionFolder = item as ICollectionFolder; - if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + if (!stubType.HasValue || stubType.Value != StubType.Folder) { - return GetMusicFolders(item, user, stubType, sort, startIndex, limit); - } - if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) - { - return GetMovieFolders(item, user, stubType, sort, startIndex, limit); - } - if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) - { - return GetTvFolders(item, user, stubType, sort, startIndex, limit); + var collectionFolder = item as ICollectionFolder; + if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return GetMusicFolders(item, user, stubType, sort, startIndex, limit); + } + if (collectionFolder != null && string.Equals(CollectionType.Movies, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return GetMovieFolders(item, user, stubType, sort, startIndex, limit); + } + if (collectionFolder != null && string.Equals(CollectionType.TvShows, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return GetTvFolders(item, user, stubType, sort, startIndex, limit); + } + + var userView = item as UserView; + if (userView != null && string.Equals(CollectionType.Folders, userView.ViewType, StringComparison.OrdinalIgnoreCase)) + { + return GetFolders(item, user, stubType, sort, startIndex, limit); + } } if (stubType.HasValue) @@ -513,7 +522,10 @@ private QueryResult GetUserItems(BaseItem item, StubType? stubType, return GetItemsFromPerson(person, user, startIndex, limit); } - return ApplyPaging(new QueryResult(), startIndex, limit); + if (stubType.Value != StubType.Folder) + { + return ApplyPaging(new QueryResult(), startIndex, limit); + } } var folder = (Folder)item; @@ -733,6 +745,23 @@ private QueryResult GetMovieFolders(BaseItem item, User user, StubTy }; } + private QueryResult GetFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) + { + var folders = user.RootFolder.GetChildren(user, true) + .OrderBy(i => i.SortName) + .Select(i => new ServerItem(i) + { + StubType = StubType.Folder + }) + .ToArray(); + + return new QueryResult + { + Items = folders, + TotalRecordCount = folders.Length + }; + } + private QueryResult GetTvFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit) { var query = new InternalItemsQuery(user) diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index bdc523c8bc..8caa086ee2 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -554,7 +554,6 @@ private void DumpProfiles() var list = new List { new SamsungSmartTvProfile(), - new Xbox360Profile(), new XboxOneProfile(), new SonyPs3Profile(), new SonyPs4Profile(), diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index 365774b0d9..eb8b178a85 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -105,7 +105,6 @@ - @@ -175,7 +174,6 @@ - diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index ba1d3a6de2..bd0a9e1f42 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -328,7 +328,7 @@ public async Task SendPlayCommand(PlayRequest command, CancellationToken cancell { if (isFirst && command.StartPositionTicks.HasValue) { - playlist.Add(CreatePlaylistItem(item, user, command.StartPositionTicks.Value, null, null, null)); + playlist.Add(CreatePlaylistItem(item, user, command.StartPositionTicks.Value, command.MediaSourceId, command.AudioStreamIndex, command.SubtitleStreamIndex)); isFirst = false; } else diff --git a/Emby.Dlna/Profiles/DefaultProfile.cs b/Emby.Dlna/Profiles/DefaultProfile.cs index 46639ee424..75204b234d 100644 --- a/Emby.Dlna/Profiles/DefaultProfile.cs +++ b/Emby.Dlna/Profiles/DefaultProfile.cs @@ -65,13 +65,15 @@ public DefaultProfile() { new DirectPlayProfile { - Container = "m4v,mpegts,ts,3gp,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,m2ts,dvr-ms", + // play all + Container = "", Type = DlnaProfileType.Video }, new DirectPlayProfile { - Container = "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac,m4a", + // play all + Container = "", Type = DlnaProfileType.Audio } }; diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs index 01e77baa25..61819c57d2 100644 --- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs +++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs @@ -58,7 +58,7 @@ public WdtvLiveProfile() Container = "avi", Type = DlnaProfileType.Video, VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,dca,mp2,mp3,pcm,dts" + AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts" }, new DirectPlayProfile @@ -66,7 +66,7 @@ public WdtvLiveProfile() Container = "mpeg", Type = DlnaProfileType.Video, VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,dca,mp2,mp3,pcm,dts" + AudioCodec = "ac3,eac3,dca,mp2,mp3,pcm,dts" }, new DirectPlayProfile @@ -74,7 +74,7 @@ public WdtvLiveProfile() Container = "mkv", Type = DlnaProfileType.Video, VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,dca,aac,mp2,mp3,pcm,dts" + AudioCodec = "ac3,eac3,dca,aac,mp2,mp3,pcm,dts" }, new DirectPlayProfile @@ -82,7 +82,7 @@ public WdtvLiveProfile() Container = "ts,m2ts", Type = DlnaProfileType.Video, VideoCodec = "mpeg1video,mpeg2video,h264,vc1", - AudioCodec = "ac3,dca,mp2,mp3,aac,dts" + AudioCodec = "ac3,eac3,dca,mp2,mp3,aac,dts" }, new DirectPlayProfile @@ -90,7 +90,7 @@ public WdtvLiveProfile() Container = "mp4,mov,m4v", Type = DlnaProfileType.Video, VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,aac,mp2,mp3,dca,dts" + AudioCodec = "ac3,eac3,aac,mp2,mp3,dca,dts" }, new DirectPlayProfile diff --git a/Emby.Dlna/Profiles/Xbox360Profile.cs b/Emby.Dlna/Profiles/Xbox360Profile.cs deleted file mode 100644 index 7bdcd2a6f8..0000000000 --- a/Emby.Dlna/Profiles/Xbox360Profile.cs +++ /dev/null @@ -1,326 +0,0 @@ -using MediaBrowser.Model.Dlna; -using System.Xml.Serialization; - -namespace Emby.Dlna.Profiles -{ - /// - /// Good info on xbox 360 requirements: https://code.google.com/p/jems/wiki/XBox360Notes - /// - [XmlRoot("Profile")] - public class Xbox360Profile : DefaultProfile - { - public Xbox360Profile() - { - Name = "Xbox 360"; - - // Required according to above - ModelName = "Windows Media Player Sharing"; - - ModelNumber = "12.0"; - - FriendlyName = "${HostName}: 1"; - - ModelUrl = "http://go.microsoft.com/fwlink/?LinkId=105926"; - Manufacturer = "Microsoft Corporation"; - ManufacturerUrl = "http://www.microsoft.com"; - XDlnaDoc = "DMS-1.50"; - ModelDescription = "Emby : UPnP Media Server"; - - TimelineOffsetSeconds = 40; - RequiresPlainFolders = true; - RequiresPlainVideoItems = true; - EnableMSMediaReceiverRegistrar = true; - - Identification = new DeviceIdentification - { - ModelName = "Xbox 360", - - Headers = new[] - { - new HttpHeaderInfo {Name = "User-Agent", Value = "Xbox", Match = HeaderMatchType.Substring}, - new HttpHeaderInfo {Name = "User-Agent", Value = "Xenon", Match = HeaderMatchType.Substring} - } - }; - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "asf", - VideoCodec = "wmv2", - AudioCodec = "wmav2", - Type = DlnaProfileType.Video, - TranscodeSeekInfo = TranscodeSeekInfo.Bytes, - EstimateContentLength = true - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "mpeg4", - AudioCodec = "ac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "avi", - VideoCodec = "h264", - AudioCodec = "aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "mp4,mov", - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Container = "asf", - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "mp3", - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }; - - ResponseProfiles = new[] - { - new ResponseProfile - { - Container = "avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - } - }; - - ContainerProfiles = new[] - { - new ContainerProfile - { - Type = DlnaProfileType.Video, - Container = "mp4,mov", - - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.Has64BitOffsets, - Value = "false", - IsRequired = false - } - } - }, - - new ContainerProfile - { - Type = DlnaProfileType.Photo, - - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - } - } - } - }; - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.Video, - Codec = "mpeg4", - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1280" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "720" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "5120000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "h264", - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoLevel, - Value = "41", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "10240000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.Video, - Codec = "wmv2,wmv3,vc1", - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Width, - Value = "1920" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.Height, - Value = "1080" - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoFramerate, - Value = "30", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.VideoBitrate, - Value = "15360000", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "ac3,wmav2,wmapro", - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "6", - IsRequired = false - } - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudio, - Codec = "aac", - Conditions = new [] - { - new ProfileCondition - { - Condition = ProfileConditionType.LessThanEqual, - Property = ProfileConditionValue.AudioChannels, - Value = "2", - IsRequired = false - }, - new ProfileCondition - { - Condition = ProfileConditionType.Equals, - Property = ProfileConditionValue.AudioProfile, - Value = "lc", - IsRequired = false - } - } - } - }; - - SubtitleProfiles = new[] - { - new SubtitleProfile - { - Format = "srt", - Method = SubtitleDeliveryMethod.Embed - } - }; - } - } -} diff --git a/Emby.Dlna/Profiles/XboxOneProfile.cs b/Emby.Dlna/Profiles/XboxOneProfile.cs index e17640f2fa..99e52510f7 100644 --- a/Emby.Dlna/Profiles/XboxOneProfile.cs +++ b/Emby.Dlna/Profiles/XboxOneProfile.cs @@ -60,7 +60,7 @@ public XboxOneProfile() new DirectPlayProfile { Container = "ts", - VideoCodec = "h264,mpeg2video", + VideoCodec = "h264,mpeg2video,hevc", AudioCodec = "ac3,aac,mp3", Type = DlnaProfileType.Video }, @@ -81,7 +81,7 @@ public XboxOneProfile() new DirectPlayProfile { Container = "mp4,mov,mkv,m4v", - VideoCodec = "h264,mpeg4,mpeg2video", + VideoCodec = "h264,mpeg4,mpeg2video,hevc", AudioCodec = "aac,ac3", Type = DlnaProfileType.Video }, diff --git a/Emby.Dlna/Profiles/Xml/Default.xml b/Emby.Dlna/Profiles/Xml/Default.xml index b07a2f7c26..133f4abf1a 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/WDTV Live.xml b/Emby.Dlna/Profiles/Xml/WDTV Live.xml index 71b3463187..44d130e929 100644 --- a/Emby.Dlna/Profiles/Xml/WDTV Live.xml +++ b/Emby.Dlna/Profiles/Xml/WDTV Live.xml @@ -36,11 +36,11 @@ true - - - - - + + + + + diff --git a/Emby.Dlna/Profiles/Xml/Xbox 360.xml b/Emby.Dlna/Profiles/Xml/Xbox 360.xml deleted file mode 100644 index 3b7d2963f2..0000000000 --- a/Emby.Dlna/Profiles/Xml/Xbox 360.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - Xbox 360 - - Xbox 360 - - - - - - ${HostName}: 1 - Microsoft Corporation - http://www.microsoft.com - Windows Media Player Sharing - Emby : UPnP Media Server - 12.0 - http://go.microsoft.com/fwlink/?LinkId=105926 - false - false - false - Audio,Photo,Video - JPEG_SM - 480 - 480 - 48 - 48 - 40000000 - 40000000 - 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 - 40 - true - true - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Emby.Dlna/Profiles/Xml/Xbox One.xml b/Emby.Dlna/Profiles/Xml/Xbox One.xml index 423327a389..6354232342 100644 --- a/Emby.Dlna/Profiles/Xml/Xbox One.xml +++ b/Emby.Dlna/Profiles/Xml/Xbox One.xml @@ -36,10 +36,10 @@ false - + - + diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj index 6024c3d2c0..f2b32d52cb 100644 --- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj +++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj @@ -63,8 +63,8 @@ - - ..\packages\SkiaSharp.1.59.2\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll + + ..\packages\SkiaSharp.1.58.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll diff --git a/Emby.Drawing.Skia/packages.config b/Emby.Drawing.Skia/packages.config index 1aa3653cd7..2b9b0aee43 100644 --- a/Emby.Drawing.Skia/packages.config +++ b/Emby.Drawing.Skia/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c1ab9ec222..745d83eb5f 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -799,7 +799,7 @@ protected virtual void OnLoggerLoaded(bool isFirstLoad) protected abstract IConnectManager CreateConnectManager(); protected abstract ISyncManager CreateSyncManager(); - + protected virtual IHttpClient CreateHttpClient() { return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent); @@ -953,6 +953,7 @@ protected async Task RegisterResources(IProgress progress) var deviceRepo = new SqliteDeviceRepository(LogManager.GetLogger("DeviceManager"), ServerConfigurationManager, FileSystemManager, JsonSerializer); deviceRepo.Initialize(); DeviceManager = new DeviceManager(deviceRepo, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager); + RegisterSingleInstance(deviceRepo); RegisterSingleInstance(DeviceManager); var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); @@ -996,7 +997,7 @@ protected async Task RegisterResources(IProgress progress) NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager); RegisterSingleInstance(NotificationManager); - SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager); + SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager, ServerConfigurationManager); RegisterSingleInstance(SubtitleManager); RegisterSingleInstance(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory)); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index c42f22804b..c566ca25bd 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -296,7 +296,7 @@ public async Task> GetDynamicMediaSources(BaseItem if (requiresCallback != null) { - results = await GetChannelItemMediaSourcesInternal(requiresCallback, GetItemExternalId(item), cancellationToken) + results = await GetChannelItemMediaSourcesInternal(requiresCallback, item.ExternalId, cancellationToken) .ConfigureAwait(false); } else @@ -990,18 +990,6 @@ public async Task> GetChannelItems(ChannelItemQuery que return result; } - private string GetItemExternalId(BaseItem item) - { - var externalId = item.ExternalId; - - if (string.IsNullOrWhiteSpace(externalId)) - { - externalId = item.GetProviderId("ProviderExternalId"); - } - - return externalId; - } - private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1); private async Task GetChannelItems(IChannel channel, User user, @@ -1080,7 +1068,7 @@ private async Task GetChannelItems(IChannel channel, { var categoryItem = _libraryManager.GetItemById(new Guid(folderId)); - query.FolderId = GetItemExternalId(categoryItem); + query.FolderId = categoryItem.ExternalId; } var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 8ff1b63c03..7ccf54d20f 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -117,7 +117,6 @@ - @@ -405,11 +404,11 @@ - + diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index cd7c98dc85..4a9e417f2e 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -16,6 +16,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Controller.IO; namespace Emby.Server.Implementations.HttpClientManager { @@ -633,12 +634,9 @@ public async Task GetTempFileResponse(HttpRequestOptions optio } else { - using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value)) + using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { - using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) - { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); - } + await StreamHelper.CopyToAsync(httpResponse.GetResponseStream(), fs, StreamDefaults.DefaultCopyToBufferSize, options.Progress, contentLength.Value, options.CancellationToken).ConfigureAwait(false); } } diff --git a/Emby.Server.Implementations/IO/ProgressStream.cs b/Emby.Server.Implementations/IO/ProgressStream.cs deleted file mode 100644 index be1ff72f8e..0000000000 --- a/Emby.Server.Implementations/IO/ProgressStream.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.IO; - -namespace Emby.Server.Implementations.IO -{ - /// - /// Measures progress when reading from a stream or writing to one - /// - public class ProgressStream : Stream - { - /// - /// Gets the base stream. - /// - /// The base stream. - public Stream BaseStream { get; private set; } - - /// - /// Gets or sets the bytes processed. - /// - /// The bytes processed. - private long BytesProcessed { get; set; } - /// - /// Gets or sets the length of the write. - /// - /// The length of the write. - private long WriteLength { get; set; } - - /// - /// Gets or sets the length of the read. - /// - /// The length of the read. - private long? ReadLength { get; set; } - - /// - /// Gets or sets the progress action. - /// - /// The progress action. - private Action ProgressAction { get; set; } - - /// - /// Creates the read progress stream. - /// - /// The base stream. - /// The progress action. - /// Length of the read. - /// ProgressStream. - public static ProgressStream CreateReadProgressStream(Stream baseStream, Action progressAction, long? readLength = null) - { - return new ProgressStream - { - BaseStream = baseStream, - ProgressAction = progressAction, - ReadLength = readLength - }; - } - - /// - /// Creates the write progress stream. - /// - /// The base stream. - /// The progress action. - /// Length of the write. - /// ProgressStream. - public static ProgressStream CreateWriteProgressStream(Stream baseStream, Action progressAction, long writeLength) - { - return new ProgressStream - { - BaseStream = baseStream, - ProgressAction = progressAction, - WriteLength = writeLength - }; - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports reading. - /// - /// true if this instance can read; otherwise, false. - /// true if the stream supports reading; otherwise, false. - public override bool CanRead - { - get { return BaseStream.CanRead; } - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking. - /// - /// true if this instance can seek; otherwise, false. - /// true if the stream supports seeking; otherwise, false. - public override bool CanSeek - { - get { return BaseStream.CanSeek; } - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports writing. - /// - /// true if this instance can write; otherwise, false. - /// true if the stream supports writing; otherwise, false. - public override bool CanWrite - { - get { return BaseStream.CanWrite; } - } - - /// - /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. - /// - public override void Flush() - { - BaseStream.Flush(); - } - - /// - /// When overridden in a derived class, gets the length in bytes of the stream. - /// - /// The length. - /// A long value representing the length of the stream in bytes. - public override long Length - { - get { return BaseStream.Length; } - } - - /// - /// When overridden in a derived class, gets or sets the position within the current stream. - /// - /// The position. - /// The current position within the stream. - public override long Position - { - get { return BaseStream.Position; } - set - { - BaseStream.Position = value; - } - } - - /// - /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - public override int Read(byte[] buffer, int offset, int count) - { - var read = BaseStream.Read(buffer, offset, count); - - BytesProcessed += read; - - double percent = BytesProcessed; - percent /= ReadLength ?? BaseStream.Length; - percent *= 100; - - ProgressAction(percent); - - return read; - } - - public override int EndRead(IAsyncResult asyncResult) - { - var read = base.EndRead(asyncResult); - - BytesProcessed += read; - - double percent = BytesProcessed; - percent /= ReadLength ?? BaseStream.Length; - percent *= 100; - - ProgressAction(percent); - - return read; - } - - /// - /// When overridden in a derived class, sets the position within the current stream. - /// - /// A byte offset relative to the parameter. - /// A value of type indicating the reference point used to obtain the new position. - /// The new position within the current stream. - public override long Seek(long offset, SeekOrigin origin) - { - return BaseStream.Seek(offset, origin); - } - - /// - /// When overridden in a derived class, sets the length of the current stream. - /// - /// The desired length of the current stream in bytes. - public override void SetLength(long value) - { - BaseStream.SetLength(value); - } - - /// - /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// - /// An array of bytes. This method copies bytes from to the current stream. - /// The zero-based byte offset in at which to begin copying bytes to the current stream. - /// The number of bytes to be written to the current stream. - public override void Write(byte[] buffer, int offset, int count) - { - BaseStream.Write(buffer, offset, count); - - BytesProcessed += count; - - double percent = BytesProcessed; - percent /= WriteLength; - percent *= 100; - - ProgressAction(percent); - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - var result = base.BeginWrite(buffer, offset, count, callback, state); - - BytesProcessed += count; - - double percent = BytesProcessed; - percent /= WriteLength; - percent *= 100; - - ProgressAction(percent); - - return result; - } - - /// - /// Releases the unmanaged resources used by the and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (disposing) - { - BaseStream.Dispose(); - } - base.Dispose(disposing); - } - } -} diff --git a/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs index 1d21796b1a..0e1f6bb008 100644 --- a/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs +++ b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs @@ -487,14 +487,17 @@ public IEnumerable GetDirectories(string path, bool recursiv AssertDirectoryExists(dir, path); var list = ListFiles(dir, recursive); + var result = new List(); foreach (var file in list) { if (file.IsDirectory()) { - yield return ToMetadata(file); + result.Add(ToMetadata(file)); } } + + return result; } public IEnumerable GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) @@ -503,6 +506,7 @@ public IEnumerable GetFiles(string path, string[] extensions AssertDirectoryExists(dir, path); var list = ListFiles(dir, recursive); + var result = new List(); foreach (var file in list) { @@ -513,10 +517,12 @@ public IEnumerable GetFiles(string path, string[] extensions if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { - yield return ToMetadata(file); + result.Add(ToMetadata(file)); } } } + + return result; } public IEnumerable GetFileSystemEntries(string path, bool recursive = false) @@ -525,15 +531,19 @@ public IEnumerable GetFileSystemEntries(string path, bool re AssertDirectoryExists(dir, path); var list = ListFiles(dir, recursive); + var result = new List(); foreach (var file in list) { - yield return ToMetadata(file); + result.Add(ToMetadata(file)); } + + return result; } - public IEnumerable GetFileSystemEntryPaths(string path, bool recursive = false) + public List GetFileSystemEntryPaths(string path, bool recursive = false) { + var result = new List(); var dir = CreateSmbDirectoryForListFiles(path); AssertDirectoryExists(dir, path); @@ -541,16 +551,18 @@ public IEnumerable GetFileSystemEntryPaths(string path, bool recursive = foreach (var file in list) { - yield return GetReturnPath(file); + result.Add(GetReturnPath(file)); } + return result; } - public IEnumerable GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) + public List GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) { var dir = CreateSmbDirectoryForListFiles(path); AssertDirectoryExists(dir, path); var list = ListFiles(dir, recursive); + var result = new List(); foreach (var file in list) { @@ -561,44 +573,52 @@ public IEnumerable GetFilePaths(string path, string[] extensions, bool e if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { - yield return filePath; + result.Add(filePath); } } } + + return result; } - public IEnumerable GetDirectoryPaths(string path, bool recursive = false) + public List GetDirectoryPaths(string path, bool recursive = false) { var dir = CreateSmbDirectoryForListFiles(path); AssertDirectoryExists(dir, path); var list = ListFiles(dir, recursive); + var result = new List(); foreach (var file in list) { if (file.IsDirectory()) { - yield return GetReturnPath(file); + result.Add(GetReturnPath(file)); } } + + return result; } private IEnumerable ListFiles(SmbFile dir, bool recursive) { var list = dir.ListFiles(); + var result = new List(); foreach (var file in list) { - yield return file; + result.Add(file); if (recursive && file.IsDirectory()) { foreach (var subFile in ListFiles(file, recursive)) { - yield return subFile; + result.Add(subFile); } } } + + return result; } } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index bd8a095503..f71e2714ac 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -709,6 +709,13 @@ public AggregateFolder CreateRootFolder() var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)); + // In case program data folder was moved + if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal)) + { + _logger.Info("Resetting root folder path to {0}", rootFolderPath); + rootFolder.Path = rootFolderPath; + } + // Add in the plug-in folders foreach (var child in PluginFolderCreators) { @@ -771,6 +778,13 @@ public Folder GetUserRootFolder() tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath)); } + // In case program data folder was moved + if (!string.Equals(tmpItem.Path, userRootPath, StringComparison.Ordinal)) + { + _logger.Info("Resetting user root folder path to {0}", userRootPath); + tmpItem.Path = userRootPath; + } + _userRootFolder = tmpItem; } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs index e2f2946db1..d30aaa133b 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -4,19 +4,26 @@ using System; using MediaBrowser.Controller.Entities; using System.IO; +using System.Linq; +using MediaBrowser.Controller.Providers; +using System.Collections.Generic; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Extensions; +using Emby.Naming.Video; +using Emby.Naming.AudioBook; namespace Emby.Server.Implementations.Library.Resolvers.Audio { /// /// Class AudioResolver /// - public class AudioResolver : ItemResolver + public class AudioResolver : ItemResolver, IMultiItemResolver { - private readonly ILibraryManager _libraryManager; + private readonly ILibraryManager LibraryManager; public AudioResolver(ILibraryManager libraryManager) { - _libraryManager = libraryManager; + LibraryManager = libraryManager; } /// @@ -25,7 +32,38 @@ public AudioResolver(ILibraryManager libraryManager) /// The priority. public override ResolverPriority Priority { - get { return ResolverPriority.Last; } + get { return ResolverPriority.Fourth; } + } + + public MultiItemResolverResult ResolveMultiple(Folder parent, + List files, + string collectionType, + IDirectoryService directoryService) + { + var result = ResolveMultipleInternal(parent, files, collectionType, directoryService); + + if (result != null) + { + foreach (var item in result.Items) + { + SetInitialItemValues((MediaBrowser.Controller.Entities.Audio.Audio)item, null); + } + } + + return result; + } + + private MultiItemResolverResult ResolveMultipleInternal(Folder parent, + List files, + string collectionType, + IDirectoryService directoryService) + { + if (string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) + { + return ResolveMultipleAudio(parent, files, directoryService, false, collectionType, true); + } + + return null; } /// @@ -37,46 +75,199 @@ protected override MediaBrowser.Controller.Entities.Audio.Audio Resolve(ItemReso { // Return audio if the path is a file and has a matching extension - if (!args.IsDirectory) + var libraryOptions = args.GetLibraryOptions(); + var collectionType = args.GetCollectionType(); + + var isBooksCollectionType = string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase); + + if (args.IsDirectory) { - var libraryOptions = args.GetLibraryOptions(); + if (!isBooksCollectionType) + { + return null; + } + + var files = args.FileSystemChildren + .Where(i => !LibraryManager.IgnoreFile(i, args.Parent)) + .ToList(); - if (_libraryManager.IsAudioFile(args.Path, libraryOptions)) + if (isBooksCollectionType) { - if (string.Equals(Path.GetExtension(args.Path), ".cue", StringComparison.OrdinalIgnoreCase)) - { - // if audio file exists of same name, return null + return FindAudio(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false); + } + + return null; + } + + if (LibraryManager.IsAudioFile(args.Path, libraryOptions)) + { + if (string.Equals(Path.GetExtension(args.Path), ".cue", StringComparison.OrdinalIgnoreCase)) + { + // if audio file exists of same name, return null + return null; + } + + var isMixedCollectionType = string.IsNullOrWhiteSpace(collectionType); + + // For conflicting extensions, give priority to videos + if (isMixedCollectionType && LibraryManager.IsVideoFile(args.Path, libraryOptions)) + { + return null; + } + + MediaBrowser.Controller.Entities.Audio.Audio item = null; + + var isMusicCollectionType = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); + + // Use regular audio type for mixed libraries, owned items and music + if (isMixedCollectionType || + args.Parent == null || + isMusicCollectionType) + { + item = new MediaBrowser.Controller.Entities.Audio.Audio(); + } + + else if (isBooksCollectionType) + { + item = new AudioBook(); + } + + if (item != null) + { + item.IsInMixedFolder = true; + } + + return item; + } + + return null; + } - return null; - } + private T FindAudio(ItemResolveArgs args, string path, Folder parent, List fileSystemEntries, IDirectoryService directoryService, string collectionType, bool parseName) + where T : MediaBrowser.Controller.Entities.Audio.Audio, new() + { + var multiDiscFolders = new List(); - var collectionType = args.GetCollectionType(); + var libraryOptions = args.GetLibraryOptions(); + var filesFromOtherItems = new List(); - var isMixed = string.IsNullOrWhiteSpace(collectionType); + // TODO: Allow GetMultiDiscMovie in here + var supportsMultiVersion = false; - // For conflicting extensions, give priority to videos - if (isMixed && _libraryManager.IsVideoFile(args.Path, libraryOptions)) - { - return null; - } + var result = ResolveMultipleAudio(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ?? + new MultiItemResolverResult(); - var isStandalone = args.Parent == null; + if (result.Items.Count == 1) + { + var videoPath = result.Items[0].Path; - if (isStandalone || - string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || - isMixed) - { - return new MediaBrowser.Controller.Entities.Audio.Audio(); - } + // If we were supporting this we'd be checking filesFromOtherItems + var hasOtherItems = false; - if (string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase)) - { - return new AudioBook(); - } + if (!hasOtherItems) + { + var item = (T)result.Items[0]; + item.IsInMixedFolder = false; + item.Name = Path.GetFileName(item.ContainingFolderPath); + return item; } } + if (result.Items.Count == 0 && multiDiscFolders.Count > 0) + { + //return GetMultiDiscAudio(multiDiscFolders, directoryService); + } + return null; } + + private MultiItemResolverResult ResolveMultipleAudio(Folder parent, IEnumerable fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType, bool parseName) + where T : MediaBrowser.Controller.Entities.Audio.Audio, new() + { + var files = new List(); + var items = new List(); + var leftOver = new List(); + + // Loop through each child file/folder and see if we find a video + foreach (var child in fileSystemEntries) + { + if (child.IsDirectory) + { + leftOver.Add(child); + } + else if (IsIgnored(child.Name)) + { + + } + else + { + files.Add(child); + } + } + + var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions(); + + var resolver = new AudioBookListResolver(namingOptions); + var resolverResult = resolver.Resolve(files).ToList(); + + var result = new MultiItemResolverResult + { + ExtraFiles = leftOver, + Items = items + }; + + var isInMixedFolder = resolverResult.Count > 1 || (parent != null && parent.IsTopParent); + + foreach (var resolvedItem in resolverResult) + { + if (resolvedItem.Files.Count > 1) + { + // For now, until we sort out naming for multi-part books + continue; + } + + var firstMedia = resolvedItem.Files.First(); + + var libraryItem = new T + { + Path = firstMedia.Path, + IsInMixedFolder = isInMixedFolder, + ProductionYear = resolvedItem.Year, + Name = parseName ? + resolvedItem.Name : + Path.GetFileNameWithoutExtension(firstMedia.Path), + //AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(), + //LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray() + }; + + result.Items.Add(libraryItem); + } + + result.ExtraFiles.AddRange(files.Where(i => !ContainsFile(resolverResult, i))); + + return result; + } + + private bool ContainsFile(List result, FileSystemMetadata file) + { + return result.Any(i => ContainsFile(i, file)); + } + + private bool ContainsFile(AudioBookInfo result, FileSystemMetadata file) + { + return result.Files.Any(i => ContainsFile(i, file)) || + result.AlternateVersions.Any(i => ContainsFile(i, file)) || + result.Extras.Any(i => ContainsFile(i, file)); + } + + private bool ContainsFile(AudioBookFileInfo result, FileSystemMetadata file) + { + return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase); + } + + private bool IsIgnored(string filename) + { + return false; + } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index e3200a0995..7e960f85e6 100644 --- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -274,7 +274,7 @@ protected bool IsDvdDirectory(string fullPath, string directoryName, IDirectoryS return false; } - return FileSystem.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase)); + return directoryService.GetFilePaths(fullPath).Any(i => string.Equals(Path.GetExtension(i), ".vob", StringComparison.OrdinalIgnoreCase)); } /// diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index d69a2b2404..6676164142 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -202,14 +202,14 @@ protected override Video Resolve(ItemResolveArgs args) { var collectionType = args.GetCollectionType(); - if (IsInvalid(args.Parent, collectionType)) - { - return null; - } - // Find movies with their own folders if (args.IsDirectory) { + if (IsInvalid(args.Parent, collectionType)) + { + return null; + } + var files = args.FileSystemChildren .Where(i => !LibraryManager.IgnoreFile(i, args.Parent)) .ToList(); @@ -251,8 +251,13 @@ protected override Video Resolve(ItemResolveArgs args) return null; } - // Owned items will be caught by the plain video resolver + // Handle owned items if (args.Parent == null) + { + return base.Resolve(args); + } + + if (IsInvalid(args.Parent, collectionType)) { return null; } @@ -528,6 +533,15 @@ private T GetMultiDiscMovie(List multiDiscFolders, IDirec return returnVideo; } + private string[] ValidCollectionTypes = new[] + { + CollectionType.Movies, + CollectionType.HomeVideos, + CollectionType.MusicVideos, + CollectionType.Movies, + CollectionType.Photos + }; + private bool IsInvalid(Folder parent, string collectionType) { if (parent != null) @@ -538,21 +552,12 @@ private bool IsInvalid(Folder parent, string collectionType) } } - var validCollectionTypes = new[] - { - CollectionType.Movies, - CollectionType.HomeVideos, - CollectionType.MusicVideos, - CollectionType.Movies, - CollectionType.Photos - }; - if (string.IsNullOrWhiteSpace(collectionType)) { return false; } - return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase); + return !ValidCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase); } private IImageProcessor _imageProcessor; diff --git a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs index 5c7a528f54..030ff88f7d 100644 --- a/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/VideoResolver.cs @@ -5,36 +5,6 @@ namespace Emby.Server.Implementations.Library.Resolvers { - /// - /// Resolves a Path into a Video - /// - public class VideoResolver : BaseVideoResolver