فهرست منبع

support conditions with direct play profiles

Luke Pulverenti 11 سال پیش
والد
کامیت
24246ba85f

+ 4 - 2
MediaBrowser.Controller/Dlna/DirectPlayProfile.cs

@@ -68,13 +68,15 @@ namespace MediaBrowser.Controller.Dlna
     public class ProfileCondition
     {
         public ProfileConditionType Condition { get; set; }
-        public ProfileConditionValue Value { get; set; }
+        public ProfileConditionValue Property { get; set; }
+        public string Value { get; set; }
     }
 
     public enum DlnaProfileType
     {
         Audio = 0,
-        Video = 1
+        Video = 1,
+        Photo = 2
     }
 
     public enum ProfileConditionType

+ 1 - 0
MediaBrowser.Dlna/MediaBrowser.Dlna.csproj

@@ -66,6 +66,7 @@
     <Compile Include="PlayTo\PlaylistItem.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="PlayTo\PlaylistItemFactory.cs" />
     <Compile Include="PlayTo\PlayToManager.cs" />
     <Compile Include="PlayTo\PlayToServerEntryPoint.cs" />
     <Compile Include="PlayTo\ServiceAction.cs" />

+ 32 - 3
MediaBrowser.Dlna/PlayTo/DlnaController.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Session;
@@ -263,7 +264,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
                 case PlaystateCommand.Seek:
                     var playlistItem = Playlist.FirstOrDefault(p => p.PlayState == 1);
-                    if (playlistItem != null && playlistItem.Transcode && playlistItem.IsVideo && _currentItem != null)
+                    if (playlistItem != null && playlistItem.Transcode && playlistItem.MediaType == DlnaProfileType.Video && _currentItem != null)
                     {
                         var newItem = CreatePlaylistItem(_currentItem, command.SeekPositionTicks ?? 0, GetServerAddress());
                         playlistItem.StartPositionTicks = newItem.StartPositionTicks;
@@ -394,11 +395,13 @@ namespace MediaBrowser.Dlna.PlayTo
 
             var deviceInfo = _device.Properties;
 
-            var playlistItem = PlaylistItem.Create(item, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()));
+            var playlistItem = GetPlaylistItem(item, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()));
             playlistItem.StartPositionTicks = startPostionTicks;
 
-            if (playlistItem.IsAudio)
+            if (playlistItem.MediaType == DlnaProfileType.Audio)
+            {
                 playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
+            }
             else
             {
                 playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress);
@@ -412,6 +415,32 @@ namespace MediaBrowser.Dlna.PlayTo
             return playlistItem;
         }
 
+        private PlaylistItem GetPlaylistItem(BaseItem item, DeviceProfile profile)
+        {
+            var video = item as Video;
+
+            if (video != null)
+            {
+                return new PlaylistItemFactory(_itemRepository).Create(video, profile);
+            }
+
+            var audio = item as Audio;
+
+            if (audio != null)
+            {
+                return new PlaylistItemFactory(_itemRepository).Create(audio, profile);
+            }
+
+            var photo = item as Photo;
+
+            if (photo != null)
+            {
+                return new PlaylistItemFactory(_itemRepository).Create(photo, profile);
+            }
+
+            throw new ArgumentException("Unrecognized item type.");
+        }
+
         /// <summary>
         /// Plays the items.
         /// </summary>

+ 3 - 75
MediaBrowser.Dlna/PlayTo/PlaylistItem.cs

@@ -1,9 +1,4 @@
 using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Linq;
 
 namespace MediaBrowser.Dlna.PlayTo
 {
@@ -11,11 +6,11 @@ namespace MediaBrowser.Dlna.PlayTo
     {
         public string ItemId { get; set; }
 
+        public string MediaSourceId { get; set; }
+        
         public bool Transcode { get; set; }
 
-        public bool IsVideo { get; set; }
-
-        public bool IsAudio { get; set; }
+        public DlnaProfileType MediaType { get; set; }
 
         public string FileFormat { get; set; }
 
@@ -30,72 +25,5 @@ namespace MediaBrowser.Dlna.PlayTo
         public string Didl { get; set; }
 
         public long StartPositionTicks { get; set; }
-
-        public static PlaylistItem Create(BaseItem item, DeviceProfile profile)
-        {
-            var playlistItem = new PlaylistItem
-            {
-                ItemId = item.Id.ToString()
-            };
-
-            DlnaProfileType profileType;
-            if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
-            {
-                playlistItem.IsVideo = true;
-                profileType = DlnaProfileType.Video;
-            }
-            else
-            {
-                playlistItem.IsAudio = true;
-                profileType = DlnaProfileType.Audio;
-            }
-
-            var path = item.Path;
-
-            var directPlay = profile.DirectPlayProfiles.FirstOrDefault(i => i.Type == profileType && IsSupported(i, path));
-
-            if (directPlay != null)
-            {
-                playlistItem.Transcode = false;
-                playlistItem.FileFormat = Path.GetExtension(path);
-                playlistItem.MimeType = directPlay.MimeType;
-                return playlistItem;
-            }
-
-            var transcodingProfile = profile.TranscodingProfiles.FirstOrDefault(i => i.Type == profileType && IsSupported(profile, i, path));
-
-            if (transcodingProfile != null)
-            {
-                playlistItem.Transcode = true;
-                //Just to make sure we have a "." for the url, remove it in case a user adds it or not
-                playlistItem.FileFormat = "." + transcodingProfile.Container.TrimStart('.');
-
-                playlistItem.MimeType = transcodingProfile.MimeType;
-            }
-
-            return playlistItem;
-        }
-
-        private static bool IsSupported(DirectPlayProfile profile, string path)
-        {
-            var mediaContainer = Path.GetExtension(path);
-
-            if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
-            {
-                return false;
-            }
-
-            // Placeholder for future conditions
-
-            // TODO: Support codec list as additional restriction
-
-            return true;
-        }
-
-        private static bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, string path)
-        {
-            // Placeholder for future conditions
-            return true;
-        }
     }
 }

+ 278 - 0
MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs

@@ -0,0 +1,278 @@
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Dlna.PlayTo
+{
+    public class PlaylistItemFactory
+    {
+        private readonly IItemRepository _itemRepo;
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+        public PlaylistItemFactory(IItemRepository itemRepo)
+        {
+            _itemRepo = itemRepo;
+        }
+
+        public PlaylistItem Create(Audio item, DeviceProfile profile)
+        {
+            var playlistItem = new PlaylistItem
+            {
+                ItemId = item.Id.ToString("N"),
+                MediaType = DlnaProfileType.Audio
+            };
+
+            var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
+            {
+                ItemId = item.Id,
+                Type = MediaStreamType.Audio
+            });
+
+            var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+
+            var directPlay = profile.DirectPlayProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
+
+            if (directPlay != null)
+            {
+                playlistItem.Transcode = false;
+                playlistItem.FileFormat = Path.GetExtension(item.Path);
+                playlistItem.MimeType = directPlay.MimeType;
+
+                return playlistItem;
+            }
+
+            var transcodingProfile = profile.TranscodingProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
+
+            if (transcodingProfile != null)
+            {
+                playlistItem.Transcode = true;
+
+                playlistItem.FileFormat = "." + transcodingProfile.Container.TrimStart('.');
+                playlistItem.MimeType = transcodingProfile.MimeType;
+            }
+
+            return playlistItem;
+        }
+
+        public PlaylistItem Create(Photo item, DeviceProfile profile)
+        {
+            var playlistItem = new PlaylistItem
+            {
+                ItemId = item.Id.ToString("N"),
+                MediaType = DlnaProfileType.Photo
+            };
+
+            var directPlay = profile.DirectPlayProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item));
+
+            if (directPlay != null)
+            {
+                playlistItem.Transcode = false;
+                playlistItem.FileFormat = Path.GetExtension(item.Path);
+                playlistItem.MimeType = directPlay.MimeType;
+
+                return playlistItem;
+            }
+
+            var transcodingProfile = profile.TranscodingProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
+
+            if (transcodingProfile != null)
+            {
+                playlistItem.Transcode = true;
+
+                playlistItem.FileFormat = "." + transcodingProfile.Container.TrimStart('.');
+                playlistItem.MimeType = transcodingProfile.MimeType;
+            }
+
+            return playlistItem;
+        }
+
+        public PlaylistItem Create(Video item, DeviceProfile profile)
+        {
+            var playlistItem = new PlaylistItem
+            {
+                ItemId = item.Id.ToString("N"),
+                MediaType = DlnaProfileType.Video
+            };
+
+            var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
+            {
+                ItemId = item.Id
+
+            }).ToList();
+
+            var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+            var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+
+            var directPlay = profile.DirectPlayProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
+
+            if (directPlay != null)
+            {
+                playlistItem.Transcode = false;
+                playlistItem.FileFormat = Path.GetExtension(item.Path);
+                playlistItem.MimeType = directPlay.MimeType;
+
+                return playlistItem;
+            }
+
+            var transcodingProfile = profile.TranscodingProfiles
+                .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(profile, i, item));
+
+            if (transcodingProfile != null)
+            {
+                playlistItem.Transcode = true;
+
+                playlistItem.FileFormat = "." + transcodingProfile.Container.TrimStart('.');
+                playlistItem.MimeType = transcodingProfile.MimeType;
+            }
+
+            return playlistItem;
+        }
+
+        private bool IsSupported(DirectPlayProfile profile, Photo item)
+        {
+            var mediaPath = item.Path;
+
+            var mediaContainer = Path.GetExtension(mediaPath);
+
+            if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
+            {
+                return false;
+            }
+
+            if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, null)))
+            {
+                return false;
+            }
+
+            return true;
+        }
+        
+        private bool IsSupported(DirectPlayProfile profile, Audio item, MediaStream audioStream)
+        {
+            var mediaPath = item.Path;
+
+            var mediaContainer = Path.GetExtension(mediaPath);
+
+            if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
+            {
+                return false;
+            }
+
+            if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, audioStream)))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool IsSupported(DirectPlayProfile profile, Video item, MediaStream videoStream, MediaStream audioStream)
+        {
+            if (item.VideoType != VideoType.VideoFile)
+            {
+                return false;
+            }
+
+            var mediaPath = item.Path;
+
+            var mediaContainer = Path.GetExtension(mediaPath);
+
+            if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase)))
+            {
+                return false;
+            }
+
+            if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream)))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Audio item)
+        {
+            // Placeholder for future conditions
+            return true;
+        }
+
+        private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Photo item)
+        {
+            // Placeholder for future conditions
+            return true;
+        }
+
+        private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Video item)
+        {
+            // Placeholder for future conditions
+            return true;
+        }
+
+        private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
+        {
+            var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream);
+
+            if (actualValue.HasValue)
+            {
+                long expected;
+                if (long.TryParse("", NumberStyles.Any, _usCulture, out expected))
+                {
+                    switch (condition.Condition)
+                    {
+                        case ProfileConditionType.Equals:
+                            return actualValue.Value == expected;
+                        case ProfileConditionType.GreaterThanEqual:
+                            return actualValue.Value >= expected;
+                        case ProfileConditionType.LessThanEqual:
+                            return actualValue.Value <= expected;
+                        case ProfileConditionType.NotEquals:
+                            return actualValue.Value != expected;
+                        default:
+                            throw new InvalidOperationException("Unexpected ProfileConditionType");
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private long? GetConditionValue(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
+        {
+            switch (condition.Property)
+            {
+                case ProfileConditionValue.AudioBitrate:
+                    return audioStream == null ? null : audioStream.BitRate;
+                case ProfileConditionValue.AudioChannels:
+                    return audioStream == null ? null : audioStream.Channels;
+                case ProfileConditionValue.Filesize:
+                    return new FileInfo(mediaPath).Length;
+                case ProfileConditionValue.VideoBitrate:
+                    return videoStream == null ? null : videoStream.BitRate;
+                case ProfileConditionValue.VideoFramerate:
+                    return videoStream == null ? null : (ConvertToLong(videoStream.AverageFrameRate ?? videoStream.RealFrameRate));
+                case ProfileConditionValue.VideoHeight:
+                    return videoStream == null ? null : videoStream.Height;
+                case ProfileConditionValue.VideoWidth:
+                    return videoStream == null ? null : videoStream.Width;
+                default:
+                    throw new InvalidOperationException("Unexpected Property");
+            }
+        }
+
+        private long? ConvertToLong(float? val)
+        {
+            return val.HasValue ? Convert.ToInt64(val.Value) : (long?)null;
+        }
+    }
+}

+ 1 - 1
MediaBrowser.Dlna/PlayTo/StreamHelper.cs

@@ -60,7 +60,7 @@ namespace MediaBrowser.Dlna.PlayTo
             {
                 contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
             }
-            else if (item.IsVideo)
+            else if (item.MediaType == Controller.Dlna.DlnaProfileType.Video)
             {
                 //Default to AVI for video
                 contentFeatures = "DLNA.ORG_PN=AVI";

+ 12 - 14
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -180,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
                     result.StatusMessage = string.Empty;
                     return;
                 }
-                
+
                 if (fileExists || otherDuplicatePaths.Count > 0)
                 {
                     result.Status = FileSortingStatus.SkippedExisting;
@@ -453,24 +453,22 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
         private bool IsSameEpisode(string sourcePath, string newPath)
         {
+            var sourceFileInfo = new FileInfo(sourcePath);
+            var destinationFileInfo = new FileInfo(newPath);
 
-                FileInfo sourceFileInfo = new FileInfo(sourcePath);
-                FileInfo destinationFileInfo = new FileInfo(newPath);
-
-                try
-                {
-                    if (sourceFileInfo.Length == destinationFileInfo.Length)
-                    {
-                        return true;
-                    }
-                }
-                catch (FileNotFoundException)
+            try
+            {
+                if (sourceFileInfo.Length == destinationFileInfo.Length)
                 {
-                    return false;
+                    return true;
                 }
-
+            }
+            catch (FileNotFoundException)
+            {
                 return false;
+            }
 
+            return false;
         }
     }
 }

+ 1 - 0
MediaBrowser.Server.Implementations/FileOrganization/NameUtils.cs

@@ -67,6 +67,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             .Replace("!", " ")
             .Replace("(", " ")
             .Replace(")", " ")
+            .Replace(":", " ")
             .Replace(",", " ")
             .Replace("-", " ")
             .Replace(" a ", String.Empty, StringComparison.OrdinalIgnoreCase)