Browse Source

Improved loading performance even more by switching from XmlDocument to XmlReader. Also added more api improvements.

LukePulverenti Luke Pulverenti luke pulverenti 13 năm trước cách đây
mục cha
commit
2e03cb0916

+ 1 - 0
MediaBrowser.Api/HttpHandlers/ImageHandler.cs

@@ -165,6 +165,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 return path;
             }
 
+            string id = QueryString["id"];
             string personName = QueryString["personname"];
             string imageType = QueryString["type"] ?? string.Empty;
             string imageIndex = QueryString["index"];

+ 105 - 0
MediaBrowser.Api/HttpHandlers/MediaHandler.cs

@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+    class MediaHandler : Response
+    {
+        public MediaHandler(RequestContext ctx)
+            : base(ctx)
+        {
+            WriteStream = s =>
+            {
+                WriteReponse(s);
+                s.Close();
+            };
+        }
+
+        private string _MediaPath = string.Empty;
+        private string MediaPath
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(_MediaPath))
+                {
+                    _MediaPath = GetMediaPath();
+                }
+
+                return _MediaPath;
+            }
+        }
+
+        private string GetMediaPath()
+        {
+            string path = QueryString["path"] ?? string.Empty;
+
+            if (!string.IsNullOrEmpty(path))
+            {
+                return path;
+            }
+
+            BaseItem item = ApiService.GetItemById(QueryString["id"]);
+
+            return item.Path;
+        }
+
+        public override string ContentType
+        {
+            get
+            {
+                // http://www.codingcereal.com/2011/10/an-array-of-45-video-mime-types/
+
+                string extension = Path.GetExtension(MediaPath);
+
+                if (extension.EndsWith("mkv", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/x-matroska";
+                }
+                else if (extension.EndsWith("avi", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/avi";
+                }
+                else if (extension.EndsWith("wmv", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/wmv";
+                }
+                else if (extension.EndsWith("m4v", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/m4v";
+                }
+                else if (extension.EndsWith("flv", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/flv";
+                }
+                else if (extension.EndsWith("mov", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/quicktime";
+                }
+                else if (extension.EndsWith("mp4", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "video/mp4";
+                }
+
+                return "video/x-matroska";
+            }
+        }
+
+        private void WriteReponse(Stream stream)
+        {
+            try
+            {
+                using (Stream input = File.OpenRead(MediaPath))
+                {
+                    input.CopyTo(stream);
+                }
+            }
+            catch
+            {
+            }
+        }
+
+    }
+}

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

@@ -54,6 +54,7 @@
     <Compile Include="HttpHandlers\PersonHandler.cs" />
     <Compile Include="HttpHandlers\RecentlyAddedItemsHandler.cs" />
     <Compile Include="ImageProcessor.cs" />
+    <Compile Include="HttpHandlers\MediaHandler.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>

+ 8 - 6
MediaBrowser.Api/Plugin.cs

@@ -13,17 +13,19 @@ namespace MediaBrowser.Api
         {
             var httpServer = Kernel.Instance.HttpServer;
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/item", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new ItemHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/media", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new MediaHandler(ctx)));
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/image", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new ImageHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/item", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new ItemHandler(ctx)));
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/genre", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new GenreHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/image", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new ImageHandler(ctx)));
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/genres", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new GenresHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/genre", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new GenreHandler(ctx)));
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/recentlyaddeditems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new RecentlyAddedItemsHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/genres", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new GenresHandler(ctx)));
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/api/inprogressitems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new InProgressItemsHandler(ctx)));
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/recentlyaddeditems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new RecentlyAddedItemsHandler(ctx)));
+
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/inprogressitems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new InProgressItemsHandler(ctx)));
         }
     }
 }

+ 4 - 0
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -33,6 +33,9 @@
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
     </Reference>
+    <Reference Include="ServiceStack.Text">
+      <HintPath>..\packages\ServiceStack.Text.3.8.5\lib\net35\ServiceStack.Text.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Reactive">
@@ -48,6 +51,7 @@
     <Compile Include="Events\GenericItemEventArgs.cs" />
     <Compile Include="Json\JsonSerializer.cs" />
     <Compile Include="Net\CollectionExtensions.cs" />
+    <Compile Include="Net\Handlers\BaseEmbeddedResourceHandler.cs" />
     <Compile Include="Net\Handlers\JsonHandler.cs" />
     <Compile Include="Net\HttpServer.cs" />
     <Compile Include="Net\Request.cs" />

+ 70 - 0
MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs

@@ -0,0 +1,70 @@
+using System.IO;
+using System.IO.Compression;
+using System;
+
+namespace MediaBrowser.Common.Net.Handlers
+{
+    public abstract class BaseEmbeddedResourceHandler : Response
+    {
+        public BaseEmbeddedResourceHandler(RequestContext ctx, string resourcePath)
+            : base(ctx)
+        {
+            ResourcePath = resourcePath;
+
+            Headers["Content-Encoding"] = "gzip";
+
+            WriteStream = s =>
+            {
+                WriteReponse(s);
+                s.Close();
+            };
+        }
+
+        protected string ResourcePath { get; set; }
+
+        public override string ContentType
+        {
+            get
+            {
+                string extension = Path.GetExtension(ResourcePath);
+
+                if (extension.EndsWith("jpeg", StringComparison.OrdinalIgnoreCase) || extension.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "image/jpeg";
+                }
+                else if (extension.EndsWith("png", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "image/png";
+                }
+                else if (extension.EndsWith("ico", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "image/ico";
+                }
+                else if (extension.EndsWith("js", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "application/x-javascript";
+                }
+                else if (extension.EndsWith("css", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "text/css";
+                }
+                else if (extension.EndsWith("html", StringComparison.OrdinalIgnoreCase))
+                {
+                    return "text/html; charset=utf-8";
+                }
+
+                return "text/plain; charset=utf-8";
+            }
+        }
+
+        private void WriteReponse(Stream stream)
+        {
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Compress, false))
+            {
+                GetEmbeddedResourceStream().CopyTo(gzipStream);
+            }
+        }
+
+        protected abstract Stream GetEmbeddedResourceStream();
+    }
+}

+ 10 - 1
MediaBrowser.Common/Net/RequestContext.cs

@@ -9,6 +9,14 @@ namespace MediaBrowser.Common.Net
         public HttpListenerRequest Request { get; private set; }
         public HttpListenerResponse Response { get; private set; }
 
+        public string LocalPath
+        {
+            get
+            {
+                return Request.Url.LocalPath;
+            }
+        }
+
         public RequestContext(HttpListenerContext context)
         {
             Response = context.Response;
@@ -19,6 +27,8 @@ namespace MediaBrowser.Common.Net
         {
             Response.AddHeader("Access-Control-Allow-Origin", "*");
 
+            Response.KeepAlive = true;
+            
             foreach (var header in handler.Headers)
             {
                 Response.AddHeader(header.Key, header.Value);
@@ -52,7 +62,6 @@ namespace MediaBrowser.Common.Net
                 {
                     CacheResponse(Response, cacheDuration, handler.LastDateModified);
                 }
-
                 handler.WriteStream(Response.OutputStream);
             }
             else

+ 1 - 0
MediaBrowser.Common/packages.config

@@ -2,4 +2,5 @@
 <packages>
   <package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
   <package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
+  <package id="ServiceStack.Text" version="3.8.5" targetFramework="net45" />
 </packages>

+ 369 - 308
MediaBrowser.Controller/Xml/BaseItemXmlParser.cs

@@ -12,15 +12,17 @@ namespace MediaBrowser.Controller.Xml
     {
         public virtual void Fetch(T item, string metadataFile)
         {
-            XmlDocument doc = new XmlDocument();
-
-            doc.Load(metadataFile);
-
-            XmlElement titleElement = doc.DocumentElement;
-
-            foreach (XmlNode node in titleElement.ChildNodes)
+            using (XmlReader reader = XmlReader.Create(metadataFile))
             {
-                FetchDataFromXmlNode(node, item);
+                reader.MoveToContent();
+
+                while (reader.Read())
+                {
+                    if (reader.NodeType == XmlNodeType.Element)
+                    {
+                        FetchDataFromXmlNode(reader, item);
+                    }
+                }
             }
 
             // If dates weren't supplied in metadata, use values from the file
@@ -35,13 +37,13 @@ namespace MediaBrowser.Controller.Xml
             }
         }
 
-        protected virtual void FetchDataFromXmlNode(XmlNode node, T item)
+        protected virtual void FetchDataFromXmlNode(XmlReader reader, T item)
         {
-            switch (node.Name)
+            switch (reader.Name)
             {
                 case "Added":
                     DateTime added;
-                    if (DateTime.TryParse(node.InnerText ?? string.Empty, out added))
+                    if (DateTime.TryParse(reader.ReadElementContentAsString() ?? string.Empty, out added))
                     {
                         item.DateCreated = added;
                     }
@@ -49,7 +51,7 @@ namespace MediaBrowser.Controller.Xml
 
                 case "Type":
                     {
-                        item.DisplayMediaType = node.InnerText ?? string.Empty;
+                        item.DisplayMediaType = reader.ReadElementContentAsString() ?? string.Empty;
 
                         switch (item.DisplayMediaType.ToLower())
                         {
@@ -68,86 +70,65 @@ namespace MediaBrowser.Controller.Xml
                     }
 
                 case "banner":
-                    item.BannerImagePath = node.InnerText ?? string.Empty;
+                    item.BannerImagePath = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "LocalTitle":
-                    item.Name = node.InnerText ?? string.Empty;
+                    item.Name = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "SortTitle":
-                    item.SortName = node.InnerText ?? string.Empty;
+                    item.SortName = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "Overview":
                 case "Description":
-                    item.Overview = node.InnerText ?? string.Empty;
+                    item.Overview = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "TagLine":
-                    item.Tagline = node.InnerText ?? string.Empty;
+                    item.Tagline = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "ContentRating":
                 case "MPAARating":
-                    item.OfficialRating = node.InnerText ?? string.Empty;
+                    item.OfficialRating = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "CustomRating":
-                    item.CustomRating = node.InnerText ?? string.Empty;
+                    item.CustomRating = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "CustomPin":
-                    item.CustomPin = node.InnerText ?? string.Empty;
-                    break;
-
-                case "Covers":
-                    FetchFromCoversNode(node, item);
-                    break;
-
-                case "Genres":
-                    FetchFromGenresNode(node, item);
+                    item.CustomPin = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "Genre":
                     {
                         var genres = (item.Genres ?? new string[] { }).ToList();
-                        genres.AddRange(GetSplitValues(node.InnerText, '|'));
+                        genres.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|'));
 
                         item.Genres = genres;
                         break;
                     }
 
                 case "AspectRatio":
-                    item.AspectRatio = node.InnerText ?? string.Empty;
-                    break;
-
-                case "Rating":
-                case "IMDBrating":
-                    float IMDBrating = node.SafeGetSingle((float)-1, (float)10);
-
-                    if (IMDBrating >= 0)
-                    {
-                        item.UserRating = IMDBrating;
-                    }
+                    item.AspectRatio = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "Network":
                     {
                         var studios = (item.Studios ?? new string[] { }).ToList();
-                        studios.AddRange(GetSplitValues(node.InnerText, '|'));
+                        studios.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|'));
 
                         item.Studios = studios;
                         break;
                     }
-                case "Studios":
-                    FetchFromStudiosNode(node, item);
-                    break;
 
                 case "Director":
                     {
-                        var list = (item.People ?? new PersonInfo[]{}).ToList();
-                        list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Director }));
+                        var list = (item.People ?? new PersonInfo[] { }).ToList();
+                        list.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Director }));
 
                         item.People = list;
                         break;
@@ -155,7 +136,7 @@ namespace MediaBrowser.Controller.Xml
                 case "Writer":
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
-                        list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Writer }));
+                        list.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Writer }));
 
                         item.People = list;
                         break;
@@ -165,28 +146,20 @@ namespace MediaBrowser.Controller.Xml
                 case "GuestStars":
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
-                        list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Actor }));
+                        list.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Actor }));
 
                         item.People = list;
                         break;
                     }
 
-                case "Persons":
-                    FetchDataFromPersonsNode(node, item);
-                    break;
-
                 case "Trailer":
-                    item.TrailerUrl = node.InnerText ?? string.Empty;
-                    break;
-
-                case "ParentalRating":
-                    FetchFromParentalRatingNode(node, item);
+                    item.TrailerUrl = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "ProductionYear":
                     {
                         int ProductionYear;
-                        if (int.TryParse(node.InnerText, out ProductionYear) && ProductionYear > 1850)
+                        if (int.TryParse(reader.ReadElementContentAsString(), out ProductionYear) && ProductionYear > 1850)
                         {
                             item.ProductionYear = ProductionYear;
                         }
@@ -194,390 +167,478 @@ namespace MediaBrowser.Controller.Xml
                         break;
                     }
 
+                case "Rating":
+                case "IMDBrating":
+
+                    string rating = reader.ReadElementContentAsString();
+
+                    if (!string.IsNullOrEmpty(rating))
+                    {
+                        float val;
+
+                        if (float.TryParse(rating, out val))
+                        {
+                            item.UserRating = val;
+                        }
+                    }
+                    break;
+
+                case "Genres":
+                    FetchFromGenresNode(reader.ReadSubtree(), item);
+                    break;
+
+                case "Persons":
+                    FetchDataFromPersonsNode(reader.ReadSubtree(), item);
+                    break;
+
+                case "ParentalRating":
+                    FetchFromParentalRatingNode(reader.ReadSubtree(), item);
+                    break;
+
+                case "Studios":
+                    FetchFromStudiosNode(reader.ReadSubtree(), item);
+                    break;
+
                 case "MediaInfo":
-                    FetchMediaInfo(node, item);
+                    FetchMediaInfo(reader.ReadSubtree(), item);
                     break;
 
                 default:
+                    reader.Skip();
                     break;
             }
         }
 
-        protected virtual void FetchFromCoversNode(XmlNode node, T item)
+        private void FetchMediaInfo(XmlReader reader, T item)
         {
-            string cover = node.SafeGetString("Front");
+            var video = item as Video;
 
-            if (!string.IsNullOrEmpty(cover))
+            if (video != null)
             {
-                item.PrimaryImagePath = cover;
+                FetchMediaInfo(reader, video);
             }
         }
 
-        protected virtual void FetchMediaInfo(XmlNode node, T item)
+        private void FetchMediaInfo(XmlReader reader, Video item)
         {
-            var iMediaInfo = item as Video;
-
-            if (iMediaInfo != null)
-            {
-                FetchMediaInfo(node, iMediaInfo);
-            }
-        }
+            reader.MoveToContent();
 
-        protected virtual void FetchMediaInfo(XmlNode node, Video item)
-        {
-            foreach (XmlNode childNode in node.ChildNodes)
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Audio":
-                        {
-                            AudioStream stream = FetchMediaInfoAudio(childNode);
+                    switch (reader.Name)
+                    {
+                        case "Audio":
+                            {
+                                AudioStream stream = FetchMediaInfoAudio(reader.ReadSubtree());
 
-                            List<AudioStream> streams = item.AudioStreams.ToList();
-                            streams.Add(stream);
-                            item.AudioStreams = streams;
+                                List<AudioStream> streams = item.AudioStreams.ToList();
+                                streams.Add(stream);
+                                item.AudioStreams = streams;
 
-                            break;
-                        }
+                                break;
+                            }
 
-                    case "Video":
-                        FetchMediaInfoVideo(childNode, item);
-                        break;
+                        case "Video":
+                            FetchMediaInfoVideo(reader.ReadSubtree(), item);
+                            break;
 
-                    case "Subtitle":
-                        FetchMediaInfoSubtitles(childNode, item);
-                        break;
+                        case "Subtitle":
+                            FetchMediaInfoSubtitles(reader.ReadSubtree(), item);
+                            break;
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
             }
         }
 
-        protected virtual AudioStream FetchMediaInfoAudio(XmlNode node)
+        private AudioStream FetchMediaInfoAudio(XmlReader reader)
         {
             AudioStream stream = new AudioStream();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "BitRate":
-                        stream.BitRate = childNode.SafeGetInt32();
-                        break;
-
-                    case "Channels":
-                        stream.Channels = childNode.SafeGetInt32();
-                        break;
+                    switch (reader.Name)
+                    {
+                        case "BitRate":
+                            stream.BitRate = reader.ReadIntSafe();
+                            break;
 
-                    case "Language":
-                        stream.Language = childNode.InnerText ?? string.Empty;
-                        break;
+                        case "Channels":
+                            stream.Channels = reader.ReadIntSafe();
+                            break;
 
-                    case "Codec":
-                        {
-                            string codec = childNode.InnerText ?? string.Empty;
+                        case "Language":
+                            stream.Language = reader.ReadElementContentAsString() ?? string.Empty;
+                            break;
 
-                            switch (codec.ToLower())
+                        case "Codec":
                             {
-                                case "dts-es":
-                                case "dts-es matrix":
-                                case "dts-es discrete":
-                                    stream.AudioFormat = "DTS";
-                                    stream.AudioProfile = "ES";
-                                    break;
-                                case "dts-hd hra":
-                                case "dts-hd high resolution":
-                                    stream.AudioFormat = "DTS";
-                                    stream.AudioProfile = "HRA";
-                                    break;
-                                case "dts ma":
-                                case "dts-hd ma":
-                                case "dts-hd master":
-                                    stream.AudioFormat = "DTS";
-                                    stream.AudioProfile = "MA";
-                                    break;
-                                case "dolby digital":
-                                case "dolby digital surround ex":
-                                case "dolby surround":
-                                    stream.AudioFormat = "AC-3";
-                                    break;
-                                case "dolby digital plus":
-                                    stream.AudioFormat = "E-AC-3";
-                                    break;
-                                case "dolby truehd":
-                                    stream.AudioFormat = "AC-3";
-                                    stream.AudioProfile = "TrueHD";
-                                    break;
-                                case "mp2":
-                                    stream.AudioFormat = "MPEG Audio";
-                                    stream.AudioProfile = "Layer 2";
-                                    break;
-                                case "other":
-                                    break;
-                                default:
-                                    stream.AudioFormat = codec;
-                                    break;
+                                string codec = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                switch (codec.ToLower())
+                                {
+                                    case "dts-es":
+                                    case "dts-es matrix":
+                                    case "dts-es discrete":
+                                        stream.AudioFormat = "DTS";
+                                        stream.AudioProfile = "ES";
+                                        break;
+                                    case "dts-hd hra":
+                                    case "dts-hd high resolution":
+                                        stream.AudioFormat = "DTS";
+                                        stream.AudioProfile = "HRA";
+                                        break;
+                                    case "dts ma":
+                                    case "dts-hd ma":
+                                    case "dts-hd master":
+                                        stream.AudioFormat = "DTS";
+                                        stream.AudioProfile = "MA";
+                                        break;
+                                    case "dolby digital":
+                                    case "dolby digital surround ex":
+                                    case "dolby surround":
+                                        stream.AudioFormat = "AC-3";
+                                        break;
+                                    case "dolby digital plus":
+                                        stream.AudioFormat = "E-AC-3";
+                                        break;
+                                    case "dolby truehd":
+                                        stream.AudioFormat = "AC-3";
+                                        stream.AudioProfile = "TrueHD";
+                                        break;
+                                    case "mp2":
+                                        stream.AudioFormat = "MPEG Audio";
+                                        stream.AudioProfile = "Layer 2";
+                                        break;
+                                    case "other":
+                                        break;
+                                    default:
+                                        stream.AudioFormat = codec;
+                                        break;
+                                }
+
+                                break;
                             }
 
+                        default:
+                            reader.Skip();
                             break;
-                        }
-
-                    default:
-                        break;
+                    }
                 }
             }
 
             return stream;
         }
 
-        protected virtual void FetchMediaInfoVideo(XmlNode node, Video item)
+        private void FetchMediaInfoVideo(XmlReader reader, Video item)
         {
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Width":
-                        item.Width = childNode.SafeGetInt32();
-                        break;
-
-                    case "Height":
-                        item.Height = childNode.SafeGetInt32();
-                        break;
+                    switch (reader.Name)
+                    {
+                        case "Width":
+                            item.Width = reader.ReadIntSafe();
+                            break;
 
-                    case "BitRate":
-                        item.VideoBitRate = childNode.SafeGetInt32();
-                        break;
+                        case "Height":
+                            item.Height = reader.ReadIntSafe();
+                            break;
 
-                    case "FrameRate":
-                        item.FrameRate = childNode.InnerText ?? string.Empty;
-                        break;
+                        case "BitRate":
+                            item.VideoBitRate = reader.ReadIntSafe();
+                            break;
 
-                    case "ScanType":
-                        item.ScanType = childNode.InnerText ?? string.Empty;
-                        break;
+                        case "FrameRate":
+                            item.FrameRate = reader.ReadElementContentAsString() ?? string.Empty;
+                            break;
 
-                    case "Duration":
-                        item.RunTime = TimeSpan.FromMinutes(childNode.SafeGetInt32());
-                        break;
+                        case "ScanType":
+                            item.ScanType = reader.ReadElementContentAsString() ?? string.Empty;
+                            break;
 
-                    case "DurationSeconds":
-                        int seconds = childNode.SafeGetInt32();
-                        if (seconds > 0)
-                        {
-                            item.RunTime = TimeSpan.FromSeconds(seconds);
-                        }
-                        break;
+                        case "Duration":
+                            item.RunTime = TimeSpan.FromMinutes(reader.ReadIntSafe());
+                            break;
 
-                    case "Codec":
-                        {
-                            string videoCodec = childNode.InnerText ?? string.Empty;
+                        case "DurationSeconds":
+                            int seconds = reader.ReadIntSafe();
+                            if (seconds > 0)
+                            {
+                                item.RunTime = TimeSpan.FromSeconds(seconds);
+                            }
+                            break;
 
-                            switch (videoCodec.ToLower())
+                        case "Codec":
                             {
-                                case "sorenson h.263":
-                                    item.VideoCodec = "Sorenson H263";
-                                    break;
-                                case "h.262":
-                                    item.VideoCodec = "MPEG-2 Video";
-                                    break;
-                                case "h.264":
-                                    item.VideoCodec = "AVC";
-                                    break;
-                                default:
-                                    item.VideoCodec = videoCodec;
-                                    break;
+                                string videoCodec = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                switch (videoCodec.ToLower())
+                                {
+                                    case "sorenson h.263":
+                                        item.VideoCodec = "Sorenson H263";
+                                        break;
+                                    case "h.262":
+                                        item.VideoCodec = "MPEG-2 Video";
+                                        break;
+                                    case "h.264":
+                                        item.VideoCodec = "AVC";
+                                        break;
+                                    default:
+                                        item.VideoCodec = videoCodec;
+                                        break;
+                                }
+
+                                break;
                             }
 
+                        default:
+                            reader.Skip();
                             break;
-                        }
-
-                    default:
-                        break;
+                    }
                 }
             }
         }
 
-        protected virtual void FetchMediaInfoSubtitles(XmlNode node, Video item)
+        private void FetchMediaInfoSubtitles(XmlReader reader, Video item)
         {
-            List<string> subtitles = item.Subtitles.ToList();
+            List<string> list = (item.Subtitles ?? new string[] { }).ToList();
+
+            reader.MoveToContent();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Language":
-                        string lang = childNode.InnerText;
+                    switch (reader.Name)
+                    {
+                        case "Language":
+                            {
+                                string genre = reader.ReadElementContentAsString();
 
-                        if (!string.IsNullOrEmpty(lang))
-                        {
-                            subtitles.Add(lang);
-                        }
-                        break;
+                                if (!string.IsNullOrEmpty(genre))
+                                {
+                                    list.Add(genre);
+                                }
+                                break;
+                            }
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
             }
 
-            item.Subtitles = subtitles;
+            item.Subtitles = list;
         }
 
-        protected virtual void FetchFromGenresNode(XmlNode node, T item)
+        private void FetchFromGenresNode(XmlReader reader, T item)
         {
             List<string> list = (item.Genres ?? new string[] { }).ToList();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Genre":
-                        string text = childNode.InnerText ?? string.Empty;
+                    switch (reader.Name)
+                    {
+                        case "Genre":
+                            {
+                                string genre = reader.ReadElementContentAsString();
 
-                        if (!string.IsNullOrEmpty(text))
-                        {
-                            list.Add(text);
-                        }
-                        break;
+                                if (!string.IsNullOrEmpty(genre))
+                                {
+                                    list.Add(genre);
+                                }
+                                break;
+                            }
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
-
             }
+
             item.Genres = list;
         }
 
-        protected virtual void FetchDataFromPersonsNode(XmlNode node, T item)
+        private void FetchDataFromPersonsNode(XmlReader reader, T item)
         {
             List<PersonInfo> list = (item.People ?? new PersonInfo[] { }).ToList();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Person":
-                        {
-                            list.Add(GetPersonFromXmlNode(childNode));
+                    switch (reader.Name)
+                    {
+                        case "Person":
+                            {
+                                list.Add(GetPersonFromXmlNode(reader));
+                                break;
+                            }
 
+                        default:
+                            reader.Skip();
                             break;
-                        }
-
-                    default:
-                        break;
+                    }
                 }
-
             }
 
             item.People = list;
         }
 
-        protected virtual void FetchFromStudiosNode(XmlNode node, T item)
+        private void FetchFromStudiosNode(XmlReader reader, T item)
         {
             List<string> list = (item.Studios ?? new string[] { }).ToList();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Studio":
-                        string text = childNode.InnerText ?? string.Empty;
+                    switch (reader.Name)
+                    {
+                        case "Studio":
+                            {
+                                string studio = reader.ReadElementContentAsString();
 
-                        if (!string.IsNullOrEmpty(text))
-                        {
-                            list.Add(text);
-                        }
-                        break;
+                                if (!string.IsNullOrEmpty(studio))
+                                {
+                                    list.Add(studio);
+                                }
+                                break;
+                            }
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
             }
 
             item.Studios = list;
         }
 
-        protected virtual void FetchFromParentalRatingNode(XmlNode node, T item)
+        private void FetchFromParentalRatingNode(XmlReader reader, T item)
         {
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Value":
-                        {
-                            int ParentalRating = childNode.SafeGetInt32((int)7);
-
-                            switch (ParentalRating)
+                    switch (reader.Name)
+                    {
+                        case "Value":
                             {
-                                case -1:
-                                    item.OfficialRating = "NR";
-                                    break;
-                                case 0:
-                                    item.OfficialRating = "UR";
-                                    break;
-                                case 1:
-                                    item.OfficialRating = "G";
-                                    break;
-                                case 3:
-                                    item.OfficialRating = "PG";
-                                    break;
-                                case 4:
-                                    item.OfficialRating = "PG-13";
-                                    break;
-                                case 5:
-                                    item.OfficialRating = "NC-17";
-                                    break;
-                                case 6:
-                                    item.OfficialRating = "R";
-                                    break;
-                                default:
-                                    break;
+                                string ratingString = reader.ReadElementContentAsString();
+
+                                int rating = 7;
+
+                                if (!string.IsNullOrEmpty(ratingString))
+                                {
+                                    int.TryParse(ratingString, out rating);
+                                }
+
+                                switch (rating)
+                                {
+                                    case -1:
+                                        item.OfficialRating = "NR";
+                                        break;
+                                    case 0:
+                                        item.OfficialRating = "UR";
+                                        break;
+                                    case 1:
+                                        item.OfficialRating = "G";
+                                        break;
+                                    case 3:
+                                        item.OfficialRating = "PG";
+                                        break;
+                                    case 4:
+                                        item.OfficialRating = "PG-13";
+                                        break;
+                                    case 5:
+                                        item.OfficialRating = "NC-17";
+                                        break;
+                                    case 6:
+                                        item.OfficialRating = "R";
+                                        break;
+                                    default:
+                                        break;
+                                }
+                                break;
                             }
-                            break;
-                        }
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
             }
         }
 
-        private PersonInfo GetPersonFromXmlNode(XmlNode node)
+        private PersonInfo GetPersonFromXmlNode(XmlReader reader)
         {
             PersonInfo person = new PersonInfo();
 
-            foreach (XmlNode childNode in node.ChildNodes)
+            reader.MoveToContent();
+
+            while (reader.Read())
             {
-                switch (childNode.Name)
+                if (reader.NodeType == XmlNodeType.Element)
                 {
-                    case "Name":
-                        person.Name = childNode.InnerText ?? string.Empty;
-                        break;
-
-                    case "Type":
-                        {
-                            string type = childNode.InnerText ?? string.Empty;
+                    switch (reader.Name)
+                    {
+                        case "Name":
+                            person.Name = reader.ReadElementContentAsString() ?? string.Empty;
+                            break;
 
-                            if (type == "Director")
+                        case "Type":
                             {
-                                person.PersonType = PersonType.Director;
-                            }
-                            else if (type == "Actor")
-                            {
-                                person.PersonType = PersonType.Actor;
+                                string type = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                if (type == "Director")
+                                {
+                                    person.PersonType = PersonType.Director;
+                                }
+                                else if (type == "Actor")
+                                {
+                                    person.PersonType = PersonType.Actor;
+                                }
+                                break;
                             }
-                            break;
-                        }
 
-                    case "Role":
-                        person.Overview = childNode.InnerText ?? string.Empty;
-                        break;
+                        case "Role":
+                            person.Overview = reader.ReadElementContentAsString() ?? string.Empty;
+                            break;
 
-                    default:
-                        break;
+                        default:
+                            reader.Skip();
+                            break;
+                    }
                 }
-
             }
+
             return person;
         }
 

+ 16 - 49
MediaBrowser.Controller/Xml/XmlExtensions.cs

@@ -6,69 +6,36 @@ namespace MediaBrowser.Controller.Xml
 {
     public static class XmlExtensions
     {
-        public static int SafeGetInt32(this XmlNode node)
-        {
-            return SafeGetInt32(node, 0);
-        }
+        private static CultureInfo _usCulture = new CultureInfo("en-US");
 
-        public static int SafeGetInt32(this XmlNode node, int defaultInt)
+        public static float ReadFloatSafe(this XmlReader reader)
         {
-            if (node != null && node.InnerText.Length > 0)
-            {
-                int rval;
-                if (Int32.TryParse(node.InnerText, out rval))
-                {
-                    return rval;
-                }
-
-            }
-            return defaultInt;
-        }
+            string valueString = reader.ReadElementContentAsString();
 
-        private static CultureInfo _usCulture = new CultureInfo("en-US");
+            float value = 0;
 
-        public static float SafeGetSingle(this XmlNode rvalNode, float minValue, float maxValue)
-        {
-            if (rvalNode.InnerText.Length > 0)
+            if (!string.IsNullOrEmpty(valueString))
             {
-                float rval;
                 // float.TryParse is local aware, so it can be probamatic, force us culture
-                if (float.TryParse(rvalNode.InnerText, NumberStyles.AllowDecimalPoint, _usCulture, out rval))
-                {
-                    if (rval >= minValue && rval <= maxValue)
-                    {
-                        return rval;
-                    }
-                }
-
+                float.TryParse(valueString, NumberStyles.AllowDecimalPoint, _usCulture, out value);
             }
-            return minValue;
-        }
-        
-        public static float SafeGetSingle(this XmlNode doc, string path, float minValue, float maxValue)
-        {
-            XmlNode rvalNode = doc.SelectSingleNode(path);
-            if (rvalNode != null)
-            {
-                rvalNode.SafeGetSingle(minValue, maxValue);
 
-            }
-            return minValue;
+            return value;
         }
 
-
-        public static string SafeGetString(this XmlNode node)
+        public static int ReadIntSafe(this XmlReader reader)
         {
-            return SafeGetString(node, null);
-        }
+            string valueString = reader.ReadElementContentAsString();
 
-        public static string SafeGetString(this XmlNode node, string defaultValue)
-        {
-            if (node != null && node.InnerText.Length > 0)
+            int value = 0;
+
+            if (!string.IsNullOrEmpty(valueString))
             {
-                return node.InnerText;
+
+                int.TryParse(valueString, out value);
             }
-            return defaultValue;
+
+            return value;
         }
     }
 }

+ 23 - 0
MediaBrowser.HtmlBrowser/Handlers/EmbeddedResourceHandler.cs

@@ -0,0 +1,23 @@
+using System.IO;
+using System.Reflection;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net.Handlers;
+
+namespace MediaBrowser.HtmlBrowser.Handlers
+{
+    class EmbeddedResourceHandler : BaseEmbeddedResourceHandler
+    {
+        public EmbeddedResourceHandler(RequestContext ctx, string resourcePath)
+            : base(ctx, resourcePath)
+        {
+      
+        }
+
+        protected override Stream GetEmbeddedResourceStream()
+        {
+            string path = ResourcePath.Replace("/", ".");
+
+            return Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.HtmlBrowser.Html." + path);
+        }
+    }
+}

+ 1 - 1
MediaBrowser.HtmlBrowser/MediaBrowser.HtmlBrowser.csproj

@@ -42,6 +42,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Handlers\EmbeddedResourceHandler.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
@@ -92,7 +93,6 @@
     <EmbeddedResource Include="Html\thirdparty\jquery.mobile110\jquery.mobile.theme-1.1.0.min.css" />
   </ItemGroup>
   <ItemGroup>
-    <Folder Include="Handlers\" />
     <Folder Include="Html\css\images\" />
     <Folder Include="Html\scripts\" />
   </ItemGroup>

+ 11 - 3
MediaBrowser.HtmlBrowser/Plugin.cs

@@ -3,6 +3,7 @@ using System.Reactive.Linq;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Controller;
+using MediaBrowser.HtmlBrowser.Handlers;
 
 namespace MediaBrowser.HtmlBrowser
 {
@@ -12,11 +13,18 @@ namespace MediaBrowser.HtmlBrowser
         {
             var httpServer = Kernel.Instance.HttpServer;
 
-            /*httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/browser/index.html", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new EmbeddedResourceHandler(ctx, "MediaBrowser.HtmlBrowser.Html.index.html")));
+            httpServer.Where(ctx => ctx.LocalPath.IndexOf("/browser/", StringComparison.OrdinalIgnoreCase) != -1).Subscribe(ctx =>
+            {
+                string localPath = ctx.LocalPath;
+                string srch = "/browser/";
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/browser/resource", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new EmbeddedResourceHandler(ctx)));
+                int index = localPath.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
 
-            httpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("/browser/favicon.ico", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new EmbeddedResourceHandler(ctx, "MediaBrowser.HtmlBrowser.Html.css.images.favicon.ico")));*/
+                string resource = localPath.Substring(index + srch.Length);
+
+                ctx.Respond(new EmbeddedResourceHandler(ctx, resource));
+
+            });
         }
     }
 }

+ 3 - 3
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -53,15 +53,15 @@
     <Compile Include="Users\UserItemData.cs" />
     <Compile Include="Entities\Video.cs" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
     </ProjectReference>
   </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 6 - 9
MediaBrowser.Movies/Metadata/MovieXmlParser.cs

@@ -1,25 +1,22 @@
-using System.Linq;
-using System.Xml;
-using MediaBrowser.Controller;
+using System.Xml;
 using MediaBrowser.Controller.Xml;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Movies.Entities;
 
 namespace MediaBrowser.Movies.Metadata
 {
     public class MovieXmlParser : BaseItemXmlParser<Movie>
     {
-        protected override void FetchDataFromXmlNode(XmlNode node, Movie item)
+        protected override void FetchDataFromXmlNode(XmlReader reader, Movie item)
         {
-            switch (node.Name)
+            switch (reader.Name)
             {
                 case "TMDbId":
-                    item.TmdbId = node.InnerText ?? string.Empty;
+                    item.TmdbId = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "IMDB":
                 case "IMDbId":
-                    string IMDbId = node.InnerText ?? string.Empty;
+                    string IMDbId = reader.ReadElementContentAsString() ?? string.Empty;
                     if (!string.IsNullOrEmpty(IMDbId))
                     {
                         item.ImdbId = IMDbId;
@@ -27,7 +24,7 @@ namespace MediaBrowser.Movies.Metadata
                     break;
 
                 default:
-                    base.FetchDataFromXmlNode(node, item);
+                    base.FetchDataFromXmlNode(reader, item);
                     break;
             }
         }

+ 8 - 9
MediaBrowser.TV/Metadata/EpisodeXmlParser.cs

@@ -1,7 +1,6 @@
 using System;
 using System.IO;
 using System.Xml;
-using MediaBrowser.Controller;
 using MediaBrowser.Controller.Xml;
 using MediaBrowser.TV.Entities;
 
@@ -9,13 +8,13 @@ namespace MediaBrowser.TV.Metadata
 {
     public class EpisodeXmlParser : BaseItemXmlParser<Episode>
     {
-        protected override void FetchDataFromXmlNode(XmlNode node, Episode item)
+        protected override void FetchDataFromXmlNode(XmlReader reader, Episode item)
         {
-            switch (node.Name)
+            switch (reader.Name)
             {
                 case "filename":
                     {
-                        string filename = node.InnerText;
+                        string filename = reader.ReadElementContentAsString();
 
                         if (!string.IsNullOrEmpty(filename))
                         {
@@ -25,20 +24,20 @@ namespace MediaBrowser.TV.Metadata
                         break;
                     }
                 case "EpisodeNumber":
-                    item.EpisodeNumber = node.InnerText ?? string.Empty;
+                    item.EpisodeNumber = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "SeasonNumber":
-                    item.SeasonNumber = node.InnerText ?? string.Empty;
+                    item.SeasonNumber = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "EpisodeName":
-                    item.Name = node.InnerText ?? string.Empty;
+                    item.Name = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "FirstAired":
                     {
-                        item.FirstAired = node.InnerText ?? string.Empty;
+                        item.FirstAired = reader.ReadElementContentAsString() ?? string.Empty;
 
                         if (!string.IsNullOrEmpty(item.FirstAired))
                         {
@@ -54,7 +53,7 @@ namespace MediaBrowser.TV.Metadata
                     }
 
                 default:
-                    base.FetchDataFromXmlNode(node, item);
+                    base.FetchDataFromXmlNode(reader, item);
                     break;
             }
         }

+ 7 - 7
MediaBrowser.TV/Metadata/SeriesXmlParser.cs

@@ -7,25 +7,25 @@ namespace MediaBrowser.TV.Metadata
 {
     public class SeriesXmlParser : BaseItemXmlParser<Series>
     {
-        protected override void FetchDataFromXmlNode(XmlNode node, Series item)
+        protected override void FetchDataFromXmlNode(XmlReader reader, Series item)
         {
-            switch (node.Name)
+            switch (reader.Name)
             {
                 case "id":
-                    item.TVDBSeriesId = node.InnerText ?? string.Empty;
+                    item.TVDBSeriesId = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "SeriesName":
-                    item.Name = node.InnerText ?? string.Empty;
+                    item.Name = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "Status":
-                    item.Status = node.InnerText ?? string.Empty;
+                    item.Status = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
 
                 case "Runtime":
                     {
-                        string text = node.InnerText ?? string.Empty;
+                        string text = reader.ReadElementContentAsString() ?? string.Empty;
                         if (!string.IsNullOrEmpty(text))
                         {
 
@@ -39,7 +39,7 @@ namespace MediaBrowser.TV.Metadata
                     }
 
                 default:
-                    base.FetchDataFromXmlNode(node, item);
+                    base.FetchDataFromXmlNode(reader, item);
                     break;
             }
         }

+ 2 - 2
MediaBrowser.sln

@@ -15,12 +15,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Program", "Med
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.InternetProviders", "MediaBrowser.InternetProviders\MediaBrowser.InternetProviders.csproj", "{5758B2C7-949A-421D-B268-70A950CF8741}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.HtmlBrowser", "MediaBrowser.HtmlBrowser\MediaBrowser.HtmlBrowser.csproj", "{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU