Explorar o código

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

LukePulverenti Luke Pulverenti luke pulverenti %!s(int64=13) %!d(string=hai) anos
pai
achega
2e03cb0916

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

@@ -165,6 +165,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 return path;
                 return path;
             }
             }
 
 
+            string id = QueryString["id"];
             string personName = QueryString["personname"];
             string personName = QueryString["personname"];
             string imageType = QueryString["type"] ?? string.Empty;
             string imageType = QueryString["type"] ?? string.Empty;
             string imageIndex = QueryString["index"];
             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\PersonHandler.cs" />
     <Compile Include="HttpHandlers\RecentlyAddedItemsHandler.cs" />
     <Compile Include="HttpHandlers\RecentlyAddedItemsHandler.cs" />
     <Compile Include="ImageProcessor.cs" />
     <Compile Include="ImageProcessor.cs" />
+    <Compile Include="HttpHandlers\MediaHandler.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   </ItemGroup>

+ 8 - 6
MediaBrowser.Api/Plugin.cs

@@ -13,17 +13,19 @@ namespace MediaBrowser.Api
         {
         {
             var httpServer = Kernel.Instance.HttpServer;
             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">
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
       <HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
     </Reference>
     </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" />
     <Reference Include="System.Core" />
     <Reference Include="System.Core" />
     <Reference Include="System.Reactive">
     <Reference Include="System.Reactive">
@@ -48,6 +51,7 @@
     <Compile Include="Events\GenericItemEventArgs.cs" />
     <Compile Include="Events\GenericItemEventArgs.cs" />
     <Compile Include="Json\JsonSerializer.cs" />
     <Compile Include="Json\JsonSerializer.cs" />
     <Compile Include="Net\CollectionExtensions.cs" />
     <Compile Include="Net\CollectionExtensions.cs" />
+    <Compile Include="Net\Handlers\BaseEmbeddedResourceHandler.cs" />
     <Compile Include="Net\Handlers\JsonHandler.cs" />
     <Compile Include="Net\Handlers\JsonHandler.cs" />
     <Compile Include="Net\HttpServer.cs" />
     <Compile Include="Net\HttpServer.cs" />
     <Compile Include="Net\Request.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 HttpListenerRequest Request { get; private set; }
         public HttpListenerResponse Response { get; private set; }
         public HttpListenerResponse Response { get; private set; }
 
 
+        public string LocalPath
+        {
+            get
+            {
+                return Request.Url.LocalPath;
+            }
+        }
+
         public RequestContext(HttpListenerContext context)
         public RequestContext(HttpListenerContext context)
         {
         {
             Response = context.Response;
             Response = context.Response;
@@ -19,6 +27,8 @@ namespace MediaBrowser.Common.Net
         {
         {
             Response.AddHeader("Access-Control-Allow-Origin", "*");
             Response.AddHeader("Access-Control-Allow-Origin", "*");
 
 
+            Response.KeepAlive = true;
+            
             foreach (var header in handler.Headers)
             foreach (var header in handler.Headers)
             {
             {
                 Response.AddHeader(header.Key, header.Value);
                 Response.AddHeader(header.Key, header.Value);
@@ -52,7 +62,6 @@ namespace MediaBrowser.Common.Net
                 {
                 {
                     CacheResponse(Response, cacheDuration, handler.LastDateModified);
                     CacheResponse(Response, cacheDuration, handler.LastDateModified);
                 }
                 }
-
                 handler.WriteStream(Response.OutputStream);
                 handler.WriteStream(Response.OutputStream);
             }
             }
             else
             else

+ 1 - 0
MediaBrowser.Common/packages.config

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

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

@@ -12,15 +12,17 @@ namespace MediaBrowser.Controller.Xml
     {
     {
         public virtual void Fetch(T item, string metadataFile)
         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
             // 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":
                 case "Added":
                     DateTime added;
                     DateTime added;
-                    if (DateTime.TryParse(node.InnerText ?? string.Empty, out added))
+                    if (DateTime.TryParse(reader.ReadElementContentAsString() ?? string.Empty, out added))
                     {
                     {
                         item.DateCreated = added;
                         item.DateCreated = added;
                     }
                     }
@@ -49,7 +51,7 @@ namespace MediaBrowser.Controller.Xml
 
 
                 case "Type":
                 case "Type":
                     {
                     {
-                        item.DisplayMediaType = node.InnerText ?? string.Empty;
+                        item.DisplayMediaType = reader.ReadElementContentAsString() ?? string.Empty;
 
 
                         switch (item.DisplayMediaType.ToLower())
                         switch (item.DisplayMediaType.ToLower())
                         {
                         {
@@ -68,86 +70,65 @@ namespace MediaBrowser.Controller.Xml
                     }
                     }
 
 
                 case "banner":
                 case "banner":
-                    item.BannerImagePath = node.InnerText ?? string.Empty;
+                    item.BannerImagePath = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "LocalTitle":
                 case "LocalTitle":
-                    item.Name = node.InnerText ?? string.Empty;
+                    item.Name = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "SortTitle":
                 case "SortTitle":
-                    item.SortName = node.InnerText ?? string.Empty;
+                    item.SortName = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "Overview":
                 case "Overview":
                 case "Description":
                 case "Description":
-                    item.Overview = node.InnerText ?? string.Empty;
+                    item.Overview = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "TagLine":
                 case "TagLine":
-                    item.Tagline = node.InnerText ?? string.Empty;
+                    item.Tagline = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "ContentRating":
                 case "ContentRating":
                 case "MPAARating":
                 case "MPAARating":
-                    item.OfficialRating = node.InnerText ?? string.Empty;
+                    item.OfficialRating = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "CustomRating":
                 case "CustomRating":
-                    item.CustomRating = node.InnerText ?? string.Empty;
+                    item.CustomRating = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "CustomPin":
                 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;
                     break;
 
 
                 case "Genre":
                 case "Genre":
                     {
                     {
                         var genres = (item.Genres ?? new string[] { }).ToList();
                         var genres = (item.Genres ?? new string[] { }).ToList();
-                        genres.AddRange(GetSplitValues(node.InnerText, '|'));
+                        genres.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|'));
 
 
                         item.Genres = genres;
                         item.Genres = genres;
                         break;
                         break;
                     }
                     }
 
 
                 case "AspectRatio":
                 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;
                     break;
 
 
                 case "Network":
                 case "Network":
                     {
                     {
                         var studios = (item.Studios ?? new string[] { }).ToList();
                         var studios = (item.Studios ?? new string[] { }).ToList();
-                        studios.AddRange(GetSplitValues(node.InnerText, '|'));
+                        studios.AddRange(GetSplitValues(reader.ReadElementContentAsString(), '|'));
 
 
                         item.Studios = studios;
                         item.Studios = studios;
                         break;
                         break;
                     }
                     }
-                case "Studios":
-                    FetchFromStudiosNode(node, item);
-                    break;
 
 
                 case "Director":
                 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;
                         item.People = list;
                         break;
                         break;
@@ -155,7 +136,7 @@ namespace MediaBrowser.Controller.Xml
                 case "Writer":
                 case "Writer":
                     {
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
                         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;
                         item.People = list;
                         break;
                         break;
@@ -165,28 +146,20 @@ namespace MediaBrowser.Controller.Xml
                 case "GuestStars":
                 case "GuestStars":
                     {
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
                         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;
                         item.People = list;
                         break;
                         break;
                     }
                     }
 
 
-                case "Persons":
-                    FetchDataFromPersonsNode(node, item);
-                    break;
-
                 case "Trailer":
                 case "Trailer":
-                    item.TrailerUrl = node.InnerText ?? string.Empty;
-                    break;
-
-                case "ParentalRating":
-                    FetchFromParentalRatingNode(node, item);
+                    item.TrailerUrl = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "ProductionYear":
                 case "ProductionYear":
                     {
                     {
                         int ProductionYear;
                         int ProductionYear;
-                        if (int.TryParse(node.InnerText, out ProductionYear) && ProductionYear > 1850)
+                        if (int.TryParse(reader.ReadElementContentAsString(), out ProductionYear) && ProductionYear > 1850)
                         {
                         {
                             item.ProductionYear = ProductionYear;
                             item.ProductionYear = ProductionYear;
                         }
                         }
@@ -194,390 +167,478 @@ namespace MediaBrowser.Controller.Xml
                         break;
                         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":
                 case "MediaInfo":
-                    FetchMediaInfo(node, item);
+                    FetchMediaInfo(reader.ReadSubtree(), item);
                     break;
                     break;
 
 
                 default:
                 default:
+                    reader.Skip();
                     break;
                     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();
             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;
                             break;
-                        }
-
-                    default:
-                        break;
+                    }
                 }
                 }
             }
             }
 
 
             return stream;
             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;
                             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();
             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;
             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();
             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;
                             break;
-                        }
-
-                    default:
-                        break;
+                    }
                 }
                 }
-
             }
             }
 
 
             item.People = list;
             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();
             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;
             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();
             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;
             return person;
         }
         }
 
 

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

@@ -6,69 +6,36 @@ namespace MediaBrowser.Controller.Xml
 {
 {
     public static class XmlExtensions
     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
                 // 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" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <Compile Include="Handlers\EmbeddedResourceHandler.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   </ItemGroup>
@@ -92,7 +93,6 @@
     <EmbeddedResource Include="Html\thirdparty\jquery.mobile110\jquery.mobile.theme-1.1.0.min.css" />
     <EmbeddedResource Include="Html\thirdparty\jquery.mobile110\jquery.mobile.theme-1.1.0.min.css" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <Folder Include="Handlers\" />
     <Folder Include="Html\css\images\" />
     <Folder Include="Html\css\images\" />
     <Folder Include="Html\scripts\" />
     <Folder Include="Html\scripts\" />
   </ItemGroup>
   </ItemGroup>

+ 11 - 3
MediaBrowser.HtmlBrowser/Plugin.cs

@@ -3,6 +3,7 @@ using System.Reactive.Linq;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
+using MediaBrowser.HtmlBrowser.Handlers;
 
 
 namespace MediaBrowser.HtmlBrowser
 namespace MediaBrowser.HtmlBrowser
 {
 {
@@ -12,11 +13,18 @@ namespace MediaBrowser.HtmlBrowser
         {
         {
             var httpServer = Kernel.Instance.HttpServer;
             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="Users\UserItemData.cs" />
     <Compile Include="Entities\Video.cs" />
     <Compile Include="Entities\Video.cs" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>
       <Name>MediaBrowser.Common</Name>
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        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.Controller.Xml;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Movies.Entities;
 using MediaBrowser.Movies.Entities;
 
 
 namespace MediaBrowser.Movies.Metadata
 namespace MediaBrowser.Movies.Metadata
 {
 {
     public class MovieXmlParser : BaseItemXmlParser<Movie>
     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":
                 case "TMDbId":
-                    item.TmdbId = node.InnerText ?? string.Empty;
+                    item.TmdbId = reader.ReadElementContentAsString() ?? string.Empty;
                     break;
                     break;
 
 
                 case "IMDB":
                 case "IMDB":
                 case "IMDbId":
                 case "IMDbId":
-                    string IMDbId = node.InnerText ?? string.Empty;
+                    string IMDbId = reader.ReadElementContentAsString() ?? string.Empty;
                     if (!string.IsNullOrEmpty(IMDbId))
                     if (!string.IsNullOrEmpty(IMDbId))
                     {
                     {
                         item.ImdbId = IMDbId;
                         item.ImdbId = IMDbId;
@@ -27,7 +24,7 @@ namespace MediaBrowser.Movies.Metadata
                     break;
                     break;
 
 
                 default:
                 default:
-                    base.FetchDataFromXmlNode(node, item);
+                    base.FetchDataFromXmlNode(reader, item);
                     break;
                     break;
             }
             }
         }
         }

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

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

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

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

+ 2 - 2
MediaBrowser.sln

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