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

This commit is contained in:
LukePulverenti Luke Pulverenti luke pulverenti 2012-07-14 16:45:11 -04:00
parent 5f5f2838b1
commit 2e03cb0916
18 changed files with 652 additions and 404 deletions

View File

@ -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"];

View File

@ -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
{
}
}
}
}

View File

@ -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>

View File

@ -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)));
} }
} }
} }

View File

@ -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" />

View File

@ -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();
}
}

View File

@ -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

View File

@ -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>

View File

@ -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(); using (XmlReader reader = XmlReader.Create(metadataFile))
doc.Load(metadataFile);
XmlElement titleElement = doc.DocumentElement;
foreach (XmlNode node in titleElement.ChildNodes)
{ {
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; item.CustomPin = reader.ReadElementContentAsString() ?? string.Empty;
break;
case "Covers":
FetchFromCoversNode(node, item);
break;
case "Genres":
FetchFromGenresNode(node, item);
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; item.AspectRatio = reader.ReadElementContentAsString() ?? string.Empty;
break;
case "Rating":
case "IMDBrating":
float IMDBrating = node.SafeGetSingle((float)-1, (float)10);
if (IMDBrating >= 0)
{
item.UserRating = IMDBrating;
}
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(); var list = (item.People ?? new PersonInfo[] { }).ToList();
list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Director })); 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; item.TrailerUrl = reader.ReadElementContentAsString() ?? string.Empty;
break;
case "ParentalRating":
FetchFromParentalRatingNode(node, item);
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; reader.MoveToContent();
if (iMediaInfo != null) while (reader.Read())
{ {
FetchMediaInfo(node, iMediaInfo); if (reader.NodeType == XmlNodeType.Element)
}
}
protected virtual void FetchMediaInfo(XmlNode node, Video item)
{
foreach (XmlNode childNode in node.ChildNodes)
{
switch (childNode.Name)
{ {
case "Audio": switch (reader.Name)
{ {
AudioStream stream = FetchMediaInfoAudio(childNode); case "Audio":
{
AudioStream stream = FetchMediaInfoAudio(reader.ReadSubtree());
List<AudioStream> streams = item.AudioStreams.ToList(); List<AudioStream> streams = item.AudioStreams.ToList();
streams.Add(stream); streams.Add(stream);
item.AudioStreams = streams; item.AudioStreams = streams;
break;
}
case "Video":
FetchMediaInfoVideo(reader.ReadSubtree(), item);
break; break;
}
case "Video": case "Subtitle":
FetchMediaInfoVideo(childNode, item); FetchMediaInfoSubtitles(reader.ReadSubtree(), item);
break; break;
case "Subtitle": default:
FetchMediaInfoSubtitles(childNode, item); reader.Skip();
break; break;
}
default:
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": switch (reader.Name)
stream.BitRate = childNode.SafeGetInt32(); {
break; case "BitRate":
stream.BitRate = reader.ReadIntSafe();
break;
case "Channels": case "Channels":
stream.Channels = childNode.SafeGetInt32(); stream.Channels = reader.ReadIntSafe();
break; break;
case "Language": case "Language":
stream.Language = childNode.InnerText ?? string.Empty; stream.Language = reader.ReadElementContentAsString() ?? string.Empty;
break; break;
case "Codec": case "Codec":
{
string codec = childNode.InnerText ?? string.Empty;
switch (codec.ToLower())
{ {
case "dts-es": string codec = reader.ReadElementContentAsString() ?? string.Empty;
case "dts-es matrix":
case "dts-es discrete": switch (codec.ToLower())
stream.AudioFormat = "DTS"; {
stream.AudioProfile = "ES"; case "dts-es":
break; case "dts-es matrix":
case "dts-hd hra": case "dts-es discrete":
case "dts-hd high resolution": stream.AudioFormat = "DTS";
stream.AudioFormat = "DTS"; stream.AudioProfile = "ES";
stream.AudioProfile = "HRA"; break;
break; case "dts-hd hra":
case "dts ma": case "dts-hd high resolution":
case "dts-hd ma": stream.AudioFormat = "DTS";
case "dts-hd master": stream.AudioProfile = "HRA";
stream.AudioFormat = "DTS"; break;
stream.AudioProfile = "MA"; case "dts ma":
break; case "dts-hd ma":
case "dolby digital": case "dts-hd master":
case "dolby digital surround ex": stream.AudioFormat = "DTS";
case "dolby surround": stream.AudioProfile = "MA";
stream.AudioFormat = "AC-3"; break;
break; case "dolby digital":
case "dolby digital plus": case "dolby digital surround ex":
stream.AudioFormat = "E-AC-3"; case "dolby surround":
break; stream.AudioFormat = "AC-3";
case "dolby truehd": break;
stream.AudioFormat = "AC-3"; case "dolby digital plus":
stream.AudioProfile = "TrueHD"; stream.AudioFormat = "E-AC-3";
break; break;
case "mp2": case "dolby truehd":
stream.AudioFormat = "MPEG Audio"; stream.AudioFormat = "AC-3";
stream.AudioProfile = "Layer 2"; stream.AudioProfile = "TrueHD";
break; break;
case "other": case "mp2":
break; stream.AudioFormat = "MPEG Audio";
default: stream.AudioProfile = "Layer 2";
stream.AudioFormat = codec; break;
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": switch (reader.Name)
item.Width = childNode.SafeGetInt32(); {
break; case "Width":
item.Width = reader.ReadIntSafe();
break;
case "Height": case "Height":
item.Height = childNode.SafeGetInt32(); item.Height = reader.ReadIntSafe();
break; break;
case "BitRate": case "BitRate":
item.VideoBitRate = childNode.SafeGetInt32(); item.VideoBitRate = reader.ReadIntSafe();
break; break;
case "FrameRate": case "FrameRate":
item.FrameRate = childNode.InnerText ?? string.Empty; item.FrameRate = reader.ReadElementContentAsString() ?? string.Empty;
break; break;
case "ScanType": case "ScanType":
item.ScanType = childNode.InnerText ?? string.Empty; item.ScanType = reader.ReadElementContentAsString() ?? string.Empty;
break; break;
case "Duration": case "Duration":
item.RunTime = TimeSpan.FromMinutes(childNode.SafeGetInt32()); item.RunTime = TimeSpan.FromMinutes(reader.ReadIntSafe());
break; break;
case "DurationSeconds": case "DurationSeconds":
int seconds = childNode.SafeGetInt32(); int seconds = reader.ReadIntSafe();
if (seconds > 0) if (seconds > 0)
{
item.RunTime = TimeSpan.FromSeconds(seconds);
}
break;
case "Codec":
{
string videoCodec = childNode.InnerText ?? string.Empty;
switch (videoCodec.ToLower())
{ {
case "sorenson h.263": item.RunTime = TimeSpan.FromSeconds(seconds);
item.VideoCodec = "Sorenson H263"; }
break; break;
case "h.262":
item.VideoCodec = "MPEG-2 Video"; case "Codec":
break; {
case "h.264": string videoCodec = reader.ReadElementContentAsString() ?? string.Empty;
item.VideoCodec = "AVC";
break; switch (videoCodec.ToLower())
default: {
item.VideoCodec = videoCodec; case "sorenson h.263":
break; 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();
foreach (XmlNode childNode in node.ChildNodes) reader.MoveToContent();
while (reader.Read())
{ {
switch (childNode.Name) if (reader.NodeType == XmlNodeType.Element)
{ {
case "Language": switch (reader.Name)
string lang = childNode.InnerText; {
case "Language":
{
string genre = reader.ReadElementContentAsString();
if (!string.IsNullOrEmpty(lang)) if (!string.IsNullOrEmpty(genre))
{ {
subtitles.Add(lang); list.Add(genre);
} }
break; break;
}
default: default:
break; 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": switch (reader.Name)
string text = childNode.InnerText ?? string.Empty; {
case "Genre":
{
string genre = reader.ReadElementContentAsString();
if (!string.IsNullOrEmpty(text)) if (!string.IsNullOrEmpty(genre))
{ {
list.Add(text); list.Add(genre);
} }
break; break;
}
default: default:
break; 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": switch (reader.Name)
{ {
list.Add(GetPersonFromXmlNode(childNode)); 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": switch (reader.Name)
string text = childNode.InnerText ?? string.Empty; {
case "Studio":
{
string studio = reader.ReadElementContentAsString();
if (!string.IsNullOrEmpty(text)) if (!string.IsNullOrEmpty(studio))
{ {
list.Add(text); list.Add(studio);
} }
break; break;
}
default: default:
break; 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": switch (reader.Name)
{ {
int ParentalRating = childNode.SafeGetInt32((int)7); case "Value":
switch (ParentalRating)
{ {
case -1: string ratingString = reader.ReadElementContentAsString();
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;
}
default: int rating = 7;
break;
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;
}
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": switch (reader.Name)
person.Name = childNode.InnerText ?? string.Empty; {
break; case "Name":
person.Name = reader.ReadElementContentAsString() ?? string.Empty;
case "Type":
{
string type = childNode.InnerText ?? string.Empty;
if (type == "Director")
{
person.PersonType = PersonType.Director;
}
else if (type == "Actor")
{
person.PersonType = PersonType.Actor;
}
break; break;
}
case "Role": case "Type":
person.Overview = childNode.InnerText ?? string.Empty; {
break; string type = reader.ReadElementContentAsString() ?? string.Empty;
default: if (type == "Director")
break; {
person.PersonType = PersonType.Director;
}
else if (type == "Actor")
{
person.PersonType = PersonType.Actor;
}
break;
}
case "Role":
person.Overview = reader.ReadElementContentAsString() ?? string.Empty;
break;
default:
reader.Skip();
break;
}
} }
} }
return person; return person;
} }

View File

@ -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);
}
public static int SafeGetInt32(this XmlNode node, int defaultInt)
{
if (node != null && node.InnerText.Length > 0)
{
int rval;
if (Int32.TryParse(node.InnerText, out rval))
{
return rval;
}
}
return defaultInt;
}
private static CultureInfo _usCulture = new CultureInfo("en-US"); private static CultureInfo _usCulture = new CultureInfo("en-US");
public static float SafeGetSingle(this XmlNode rvalNode, float minValue, float maxValue) public static float ReadFloatSafe(this XmlReader reader)
{ {
if (rvalNode.InnerText.Length > 0) string valueString = reader.ReadElementContentAsString();
float value = 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)) float.TryParse(valueString, NumberStyles.AllowDecimalPoint, _usCulture, out value);
{
if (rval >= minValue && rval <= maxValue)
{
return rval;
}
}
} }
return minValue;
return value;
} }
public static float SafeGetSingle(this XmlNode doc, string path, float minValue, float maxValue) public static int ReadIntSafe(this XmlReader reader)
{ {
XmlNode rvalNode = doc.SelectSingleNode(path); string valueString = reader.ReadElementContentAsString();
if (rvalNode != null)
int value = 0;
if (!string.IsNullOrEmpty(valueString))
{ {
rvalNode.SafeGetSingle(minValue, maxValue);
int.TryParse(valueString, out value);
} }
return minValue;
}
return value;
public static string SafeGetString(this XmlNode node)
{
return SafeGetString(node, null);
}
public static string SafeGetString(this XmlNode node, string defaultValue)
{
if (node != null && node.InnerText.Length > 0)
{
return node.InnerText;
}
return defaultValue;
} }
} }
} }

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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));
});
} }
} }
} }

View File

@ -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.

View File

@ -1,25 +1,22 @@
using System.Linq; using System.Xml;
using System.Xml;
using MediaBrowser.Controller;
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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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