Initial check-in
This commit is contained in:
commit
b50f78e5da
37
.hgignore
Normal file
37
.hgignore
Normal file
|
@ -0,0 +1,37 @@
|
|||
# use glob syntax
|
||||
syntax: glob
|
||||
|
||||
*.obj
|
||||
*.pdb
|
||||
*.user
|
||||
*.aps
|
||||
*.pch
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ncb
|
||||
*.suo
|
||||
*.tlb
|
||||
*.tlh
|
||||
*.bak
|
||||
*.cache
|
||||
*.ilk
|
||||
*.log
|
||||
*.lib
|
||||
*.sbr
|
||||
*.scc
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
[Tt]humbs.db
|
||||
[Tt]est[Rr]esult*
|
||||
[Bb]uild[Ll]og.*
|
||||
*.[Pp]ublish.xml
|
||||
*.resharper
|
||||
|
||||
# ncrunch files
|
||||
*.ncrunchsolution
|
||||
*.ncrunchproject
|
14
MediaBrowser.Api/HttpHandlers/ImageHandler.cs
Normal file
14
MediaBrowser.Api/HttpHandlers/ImageHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using MediaBrowser.Controller.Net;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using MediaBrowser.Common.Json;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace MediaBrowser.Api.HttpHandlers
|
||||
{
|
||||
class ImageHandler
|
||||
{
|
||||
}
|
||||
}
|
93
MediaBrowser.Api/HttpHandlers/ItemHandler.cs
Normal file
93
MediaBrowser.Api/HttpHandlers/ItemHandler.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
using MediaBrowser.Controller.Net;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using MediaBrowser.Common.Json;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace MediaBrowser.Api.HttpHandlers
|
||||
{
|
||||
public class ItemHandler : Response
|
||||
{
|
||||
public ItemHandler(RequestContext ctx)
|
||||
: base(ctx)
|
||||
{
|
||||
ContentType = "application/json";
|
||||
|
||||
Headers["Content-Encoding"] = "gzip";
|
||||
|
||||
WriteStream = s =>
|
||||
{
|
||||
WriteReponse(s);
|
||||
s.Close();
|
||||
};
|
||||
}
|
||||
|
||||
private Guid ItemId
|
||||
{
|
||||
get
|
||||
{
|
||||
string id = RequestContext.Request.QueryString["id"];
|
||||
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
return Guid.Parse(id);
|
||||
}
|
||||
}
|
||||
|
||||
BaseItem Item
|
||||
{
|
||||
get
|
||||
{
|
||||
Guid id = ItemId;
|
||||
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Kernel.Instance.RootFolder;
|
||||
}
|
||||
|
||||
return Kernel.Instance.RootFolder.FindById(id);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteReponse(Stream stream)
|
||||
{
|
||||
BaseItem item = Item;
|
||||
|
||||
object returnObject;
|
||||
|
||||
Folder folder = item as Folder;
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
returnObject = new
|
||||
{
|
||||
Item = item,
|
||||
Children = folder.Children
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
returnObject = new
|
||||
{
|
||||
Item = item
|
||||
};
|
||||
}
|
||||
|
||||
WriteJsonResponse(returnObject, stream);
|
||||
}
|
||||
|
||||
private void WriteJsonResponse(object obj, Stream stream)
|
||||
{
|
||||
using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Compress, false))
|
||||
{
|
||||
JsonSerializer.Serialize(obj, gzipStream);
|
||||
//gzipStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
MediaBrowser.Api/MediaBrowser.Api.csproj
Normal file
79
MediaBrowser.Api/MediaBrowser.Api.csproj
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4FD51AC5-2C16-4308-A993-C3A84F3B4582}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Api</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Api</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Reactive, Version=1.0.10621.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="HttpHandlers\ImageHandler.cs" />
|
||||
<Compile Include="HttpHandlers\ItemHandler.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
33
MediaBrowser.Api/Plugin.cs
Normal file
33
MediaBrowser.Api/Plugin.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Linq;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Api.HttpHandlers;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
{
|
||||
public class Plugin : BasePlugin<BasePluginConfiguration>
|
||||
{
|
||||
List<IDisposable> HttpHandlers = new List<IDisposable>();
|
||||
|
||||
protected override void InitInternal()
|
||||
{
|
||||
HttpHandlers.Add(Kernel.Instance.HttpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("mediabrowser/api/item")).Subscribe(ctx => ctx.Respond(new ItemHandler(ctx))));
|
||||
HttpHandlers.Add(Kernel.Instance.HttpServer.Where(ctx => ctx.Request.Url.LocalPath.EndsWith("mediabrowser/api/image")).Subscribe(ctx => ctx.Respond(new ItemHandler(ctx))));
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
foreach (var handler in HttpHandlers)
|
||||
{
|
||||
handler.Dispose();
|
||||
}
|
||||
|
||||
HttpHandlers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Api/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Api/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Api")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Api")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("13464b02-f033-48b8-9e1c-d071f8860935")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
4
MediaBrowser.Api/packages.config
Normal file
4
MediaBrowser.Api/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
|
||||
</packages>
|
9
MediaBrowser.Common/Events/GenericItemEventArgs.cs
Normal file
9
MediaBrowser.Common/Events/GenericItemEventArgs.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace MediaBrowser.Common.Events
|
||||
{
|
||||
public class GenericItemEventArgs<TItemType> : EventArgs
|
||||
{
|
||||
public TItemType Item { get; set; }
|
||||
}
|
||||
}
|
55
MediaBrowser.Common/Json/JsonSerializer.cs
Normal file
55
MediaBrowser.Common/Json/JsonSerializer.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Common.Json
|
||||
{
|
||||
public class JsonSerializer
|
||||
{
|
||||
public static void Serialize<T>(T o, Stream stream)
|
||||
{
|
||||
using (StreamWriter streamWriter = new StreamWriter(stream))
|
||||
{
|
||||
using (Newtonsoft.Json.JsonTextWriter writer = new Newtonsoft.Json.JsonTextWriter(streamWriter))
|
||||
{
|
||||
var settings = new Newtonsoft.Json.JsonSerializerSettings()
|
||||
{
|
||||
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
Newtonsoft.Json.JsonSerializer.Create(settings).Serialize(writer, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Serialize<T>(T o, string file)
|
||||
{
|
||||
using (StreamWriter streamWriter = new StreamWriter(file))
|
||||
{
|
||||
using (Newtonsoft.Json.JsonTextWriter writer = new Newtonsoft.Json.JsonTextWriter(streamWriter))
|
||||
{
|
||||
var settings = new Newtonsoft.Json.JsonSerializerSettings()
|
||||
{
|
||||
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
Newtonsoft.Json.JsonSerializer.Create(settings).Serialize(writer, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string file)
|
||||
{
|
||||
using (StreamReader streamReader = new StreamReader(file))
|
||||
{
|
||||
using (Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(streamReader))
|
||||
{
|
||||
return Newtonsoft.Json.JsonSerializer.Create(new Newtonsoft.Json.JsonSerializerSettings() { }).Deserialize<T>(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
MediaBrowser.Common/Logging/BaseLogger.cs
Normal file
80
MediaBrowser.Common/Logging/BaseLogger.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Common.Logging
|
||||
{
|
||||
public abstract class BaseLogger
|
||||
{
|
||||
public LogSeverity LogSeverity { get; set; }
|
||||
|
||||
public void LogInfo(string message, params object[] paramList)
|
||||
{
|
||||
LogEntry(message, LogSeverity.Info, paramList);
|
||||
}
|
||||
|
||||
public void LogDebugInfo(string message, params object[] paramList)
|
||||
{
|
||||
LogEntry(message, LogSeverity.Debug, paramList);
|
||||
}
|
||||
|
||||
public void LogError(string message, params object[] paramList)
|
||||
{
|
||||
LogEntry(message, LogSeverity.Error, paramList);
|
||||
}
|
||||
|
||||
public void LogException(string message, Exception exception, params object[] paramList)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
var trace = new StackTrace(exception, true);
|
||||
builder.AppendFormat("Exception. Type={0} Msg={1} Src={2} Method={5} Line={6} Col={7}{4}StackTrace={4}{3}",
|
||||
exception.GetType().FullName,
|
||||
exception.Message,
|
||||
exception.Source,
|
||||
exception.StackTrace,
|
||||
Environment.NewLine,
|
||||
trace.GetFrame(0).GetMethod().Name,
|
||||
trace.GetFrame(0).GetFileLineNumber(),
|
||||
trace.GetFrame(0).GetFileColumnNumber());
|
||||
}
|
||||
|
||||
StackFrame frame = new StackFrame(1);
|
||||
|
||||
message = string.Format(message, paramList);
|
||||
|
||||
LogError(string.Format("{0} ( {1} )", message, builder));
|
||||
}
|
||||
|
||||
public void LogWarning(string message, params object[] paramList)
|
||||
{
|
||||
LogEntry(message, LogSeverity.Warning, paramList);
|
||||
}
|
||||
|
||||
private void LogEntry(string message, LogSeverity severity, params object[] paramList)
|
||||
{
|
||||
if (severity < LogSeverity) return;
|
||||
|
||||
message = string.Format(message, paramList);
|
||||
|
||||
Thread currentThread = Thread.CurrentThread;
|
||||
|
||||
LogRow row = new LogRow()
|
||||
{
|
||||
Severity = severity,
|
||||
Message = message,
|
||||
Category = string.Empty,
|
||||
ThreadId = currentThread.ManagedThreadId,
|
||||
ThreadName = currentThread.Name,
|
||||
Time = DateTime.Now
|
||||
};
|
||||
|
||||
LogEntry(row);
|
||||
}
|
||||
|
||||
protected abstract void LogEntry(LogRow row);
|
||||
}
|
||||
}
|
55
MediaBrowser.Common/Logging/FileLogger.cs
Normal file
55
MediaBrowser.Common/Logging/FileLogger.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Common.Logging
|
||||
{
|
||||
public class FileLogger : BaseLogger, IDisposable
|
||||
{
|
||||
private string LogDirectory { get; set; }
|
||||
private string CurrentLogFile { get; set; }
|
||||
|
||||
private FileStream FileStream { get; set; }
|
||||
|
||||
public FileLogger(string logDirectory)
|
||||
{
|
||||
LogDirectory = logDirectory;
|
||||
}
|
||||
|
||||
private void EnsureStream()
|
||||
{
|
||||
if (FileStream == null)
|
||||
{
|
||||
if (!Directory.Exists(LogDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(LogDirectory);
|
||||
}
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
CurrentLogFile = Path.Combine(LogDirectory, now.ToString("dMyyyy") + "-" + now.Ticks + ".log");
|
||||
|
||||
FileStream = new FileStream(CurrentLogFile, FileMode.Append, FileAccess.Write, FileShare.Read);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LogEntry(LogRow row)
|
||||
{
|
||||
EnsureStream();
|
||||
|
||||
byte[] bytes = new UTF8Encoding().GetBytes(row.ToString() + Environment.NewLine);
|
||||
|
||||
FileStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
FileStream.Flush();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (FileStream != null)
|
||||
{
|
||||
FileStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
MediaBrowser.Common/Logging/LogRow.cs
Normal file
118
MediaBrowser.Common/Logging/LogRow.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Common.Logging
|
||||
{
|
||||
public struct LogRow
|
||||
{
|
||||
|
||||
const string TimePattern = "h:mm:ss.fff tt d/M/yyyy";
|
||||
|
||||
|
||||
public LogSeverity Severity { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string Category { get; set; }
|
||||
public int ThreadId { get; set; }
|
||||
public string ThreadName { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
|
||||
public string ShortMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
var message = Message;
|
||||
if (message.Length > 120)
|
||||
{
|
||||
message = Message.Substring(0, 120).Replace(Environment.NewLine, " ") + " ... ";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
public string FullDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendFormat("Time: {0}", Time);
|
||||
sb.AppendLine();
|
||||
sb.AppendFormat("Thread Id: {0} {1}", ThreadId, ThreadName);
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(Message);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append(Time.ToString(TimePattern))
|
||||
.Append(" , ")
|
||||
.Append(Enum.GetName(typeof(LogSeverity), Severity))
|
||||
.Append(" , ")
|
||||
.Append(Encode(Message))
|
||||
.Append(" , ")
|
||||
.Append(Encode(Category))
|
||||
.Append(" , ")
|
||||
.Append(ThreadId)
|
||||
.Append(" , ")
|
||||
.Append(Encode(ThreadName));
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private string Encode(string str)
|
||||
{
|
||||
return (str ?? "").Replace(",", ",,").Replace(Environment.NewLine, " [n] ");
|
||||
}
|
||||
|
||||
public static LogRow FromString(string message)
|
||||
{
|
||||
var split = splitString(message);
|
||||
return new LogRow()
|
||||
{
|
||||
Time = DateTime.ParseExact(split[0], TimePattern, null),
|
||||
Severity = (LogSeverity)Enum.Parse(typeof(LogSeverity), split[1]),
|
||||
Message = split[2],
|
||||
Category = split[3],
|
||||
ThreadId = int.Parse(split[4]),
|
||||
ThreadName = split[5]
|
||||
};
|
||||
}
|
||||
|
||||
static string[] splitString(string message)
|
||||
{
|
||||
List<string> items = new List<string>();
|
||||
bool gotComma = false;
|
||||
|
||||
StringBuilder currentItem = new StringBuilder();
|
||||
|
||||
foreach (var chr in message)
|
||||
{
|
||||
|
||||
if (chr == ',' && gotComma)
|
||||
{
|
||||
gotComma = false;
|
||||
currentItem.Append(',');
|
||||
}
|
||||
else if (chr == ',')
|
||||
{
|
||||
gotComma = true;
|
||||
}
|
||||
else if (gotComma)
|
||||
{
|
||||
items.Add(currentItem.ToString().Replace(" [n] ", Environment.NewLine).Trim());
|
||||
currentItem = new StringBuilder();
|
||||
gotComma = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentItem.Append(chr);
|
||||
}
|
||||
|
||||
}
|
||||
items.Add(currentItem.ToString().Replace("[n]", Environment.NewLine).Trim());
|
||||
return items.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
18
MediaBrowser.Common/Logging/LogSeverity.cs
Normal file
18
MediaBrowser.Common/Logging/LogSeverity.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Logging
|
||||
{
|
||||
[Flags]
|
||||
public enum LogSeverity
|
||||
{
|
||||
None = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warning = 4,
|
||||
Error = 8
|
||||
}
|
||||
}
|
38
MediaBrowser.Common/Logging/Logger.cs
Normal file
38
MediaBrowser.Common/Logging/Logger.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Logging
|
||||
{
|
||||
public static class Logger
|
||||
{
|
||||
public static BaseLogger LoggerInstance { get; set; }
|
||||
|
||||
public static void LogInfo(string message, params object[] paramList)
|
||||
{
|
||||
LoggerInstance.LogInfo(message, paramList);
|
||||
}
|
||||
|
||||
public static void LogDebugInfo(string message, params object[] paramList)
|
||||
{
|
||||
LoggerInstance.LogDebugInfo(message, paramList);
|
||||
}
|
||||
|
||||
public static void LogError(string message, params object[] paramList)
|
||||
{
|
||||
LoggerInstance.LogError(message, paramList);
|
||||
}
|
||||
|
||||
public static void LogException(string message, Exception ex, params object[] paramList)
|
||||
{
|
||||
LoggerInstance.LogException(message, ex, paramList);
|
||||
}
|
||||
|
||||
public static void LogWarning(string message, params object[] paramList)
|
||||
{
|
||||
LoggerInstance.LogWarning(message, paramList);
|
||||
}
|
||||
}
|
||||
}
|
68
MediaBrowser.Common/MediaBrowser.Common.csproj
Normal file
68
MediaBrowser.Common/MediaBrowser.Common.csproj
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Common</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Common</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Events\GenericItemEventArgs.cs" />
|
||||
<Compile Include="Json\JsonSerializer.cs" />
|
||||
<Compile Include="Plugins\BasePluginConfiguration.cs" />
|
||||
<Compile Include="Logging\BaseLogger.cs" />
|
||||
<Compile Include="Logging\FileLogger.cs" />
|
||||
<Compile Include="Logging\Logger.cs" />
|
||||
<Compile Include="Logging\LogRow.cs" />
|
||||
<Compile Include="Logging\LogSeverity.cs" />
|
||||
<Compile Include="Plugins\BasePlugin.cs" />
|
||||
<Compile Include="Plugins\PluginController.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
58
MediaBrowser.Common/Plugins/BasePlugin.cs
Normal file
58
MediaBrowser.Common/Plugins/BasePlugin.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using MediaBrowser.Common.Json;
|
||||
|
||||
namespace MediaBrowser.Common.Plugins
|
||||
{
|
||||
public abstract class BasePlugin<TConfigurationType> : IDisposable, IPlugin
|
||||
where TConfigurationType : BasePluginConfiguration, new()
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public TConfigurationType Configuration { get; private set; }
|
||||
|
||||
private string ConfigurationPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.IO.Path.Combine(Path, "config.js");
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Configuration = GetConfiguration();
|
||||
|
||||
if (Configuration.Enabled)
|
||||
{
|
||||
InitInternal();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void InitInternal();
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
private TConfigurationType GetConfiguration()
|
||||
{
|
||||
if (!File.Exists(ConfigurationPath))
|
||||
{
|
||||
return new TConfigurationType();
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<TConfigurationType>(ConfigurationPath);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPlugin
|
||||
{
|
||||
string Path { get; set; }
|
||||
|
||||
void Init();
|
||||
void Dispose();
|
||||
}
|
||||
}
|
18
MediaBrowser.Common/Plugins/BasePluginConfiguration.cs
Normal file
18
MediaBrowser.Common/Plugins/BasePluginConfiguration.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Plugins
|
||||
{
|
||||
public class BasePluginConfiguration
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public BasePluginConfiguration()
|
||||
{
|
||||
Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
90
MediaBrowser.Common/Plugins/PluginController.cs
Normal file
90
MediaBrowser.Common/Plugins/PluginController.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MediaBrowser.Common.Plugins
|
||||
{
|
||||
public class PluginController
|
||||
{
|
||||
public string PluginsPath { get; set; }
|
||||
|
||||
public PluginController(string pluginFolderPath)
|
||||
{
|
||||
PluginsPath = pluginFolderPath;
|
||||
}
|
||||
|
||||
public IEnumerable<IPlugin> GetAllPlugins()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||
|
||||
if (!Directory.Exists(PluginsPath))
|
||||
{
|
||||
Directory.CreateDirectory(PluginsPath);
|
||||
}
|
||||
|
||||
List<IPlugin> plugins = new List<IPlugin>();
|
||||
|
||||
foreach (string folder in Directory.GetDirectories(PluginsPath, "*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
IPlugin plugin = GetPluginFromDirectory(folder);
|
||||
|
||||
plugin.Path = folder;
|
||||
|
||||
if (plugin != null)
|
||||
{
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
private IPlugin GetPluginFromDirectory(string path)
|
||||
{
|
||||
string dll = Directory.GetFiles(path, "*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault();
|
||||
|
||||
if (!string.IsNullOrEmpty(dll))
|
||||
{
|
||||
return GetPluginFromDll(dll);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IPlugin GetPluginFromDll(string path)
|
||||
{
|
||||
return FindPlugin(Assembly.Load(File.ReadAllBytes(path)));
|
||||
}
|
||||
|
||||
private IPlugin FindPlugin(Assembly assembly)
|
||||
{
|
||||
var plugin = assembly.GetTypes().Where(type => typeof(IPlugin).IsAssignableFrom(type)).FirstOrDefault();
|
||||
|
||||
if (plugin != null)
|
||||
{
|
||||
return plugin.GetConstructor(Type.EmptyTypes).Invoke(null) as IPlugin;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
AssemblyName assemblyName = new AssemblyName(args.Name);
|
||||
|
||||
IEnumerable<string> dllPaths = Directory.GetFiles(PluginsPath, "*.dll", SearchOption.AllDirectories);
|
||||
|
||||
string dll = dllPaths.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f) == assemblyName.Name);
|
||||
|
||||
if (!string.IsNullOrEmpty(dll))
|
||||
{
|
||||
return Assembly.Load(File.ReadAllBytes(dll));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Common/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Common/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Common")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Common")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("cdec1bb7-6ffd-409f-b41f-0524a73df9be")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
4
MediaBrowser.Common/packages.config
Normal file
4
MediaBrowser.Common/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
|
||||
</packages>
|
77
MediaBrowser.Configuration/MediaBrowser.Configuration.csproj
Normal file
77
MediaBrowser.Configuration/MediaBrowser.Configuration.csproj
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{933CC468-E22B-48D8-8BCA-2E026F411CA2}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Configuration</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Configuration</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Reactive, Version=1.0.10621.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
11
MediaBrowser.Configuration/Plugin.cs
Normal file
11
MediaBrowser.Configuration/Plugin.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using MediaBrowser.Common.Plugins;
|
||||
|
||||
namespace MediaBrowser.Configuration
|
||||
{
|
||||
public class Plugin : BasePlugin<BasePluginConfiguration>
|
||||
{
|
||||
protected override void InitInternal()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Configuration/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Configuration/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Configuration")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Configuration")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c109d2b1-2368-43a2-bed1-ec2cfb33e741")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
4
MediaBrowser.Configuration/packages.config
Normal file
4
MediaBrowser.Configuration/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
|
||||
</packages>
|
94
MediaBrowser.Controller/Events/ItemResolveEventArgs.cs
Normal file
94
MediaBrowser.Controller/Events/ItemResolveEventArgs.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Events
|
||||
{
|
||||
public class ItemResolveEventArgs : PreBeginResolveEventArgs
|
||||
{
|
||||
public IEnumerable<KeyValuePair<string, FileAttributes>> FileSystemChildren { get; set; }
|
||||
|
||||
public KeyValuePair<string, FileAttributes>? GetFolderByName(string name)
|
||||
{
|
||||
foreach (KeyValuePair<string, FileAttributes> entry in FileSystemChildren)
|
||||
{
|
||||
if (!entry.Value.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (System.IO.Path.GetFileName(entry.Key).Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public KeyValuePair<string, FileAttributes>? GetFileByName(string name)
|
||||
{
|
||||
foreach (KeyValuePair<string, FileAttributes> entry in FileSystemChildren)
|
||||
{
|
||||
if (entry.Value.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (System.IO.Path.GetFileName(entry.Key).Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool ContainsFile(string name)
|
||||
{
|
||||
return GetFileByName(name) != null;
|
||||
}
|
||||
|
||||
public bool ContainsFolder(string name)
|
||||
{
|
||||
return GetFolderByName(name) != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class PreBeginResolveEventArgs : EventArgs
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public BaseItem Parent { get; set; }
|
||||
|
||||
public bool Cancel { get; set; }
|
||||
|
||||
public FileAttributes FileAttributes { get; set; }
|
||||
|
||||
public bool IsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return FileAttributes.HasFlag(FileAttributes.Directory);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHidden
|
||||
{
|
||||
get
|
||||
{
|
||||
return FileAttributes.HasFlag(FileAttributes.Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSystemFile
|
||||
{
|
||||
get
|
||||
{
|
||||
return FileAttributes.HasFlag(FileAttributes.System);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
152
MediaBrowser.Controller/IO/DirectoryWatchers.cs
Normal file
152
MediaBrowser.Controller/IO/DirectoryWatchers.cs
Normal file
|
@ -0,0 +1,152 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.IO
|
||||
{
|
||||
public class DirectoryWatchers
|
||||
{
|
||||
private List<FileSystemWatcher> FileSystemWatchers = new List<FileSystemWatcher>();
|
||||
private Timer updateTimer = null;
|
||||
private List<string> affectedPaths = new List<string>();
|
||||
|
||||
private const int TimerDelayInSeconds = 5;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
List<string> pathsToWatch = new List<string>();
|
||||
|
||||
var rootFolder = Kernel.Instance.RootFolder;
|
||||
|
||||
pathsToWatch.Add(rootFolder.Path);
|
||||
|
||||
foreach (Folder folder in rootFolder.FolderChildren)
|
||||
{
|
||||
foreach (Folder subFolder in folder.FolderChildren)
|
||||
{
|
||||
if (Path.IsPathRooted(subFolder.Path))
|
||||
{
|
||||
string parent = Path.GetDirectoryName(subFolder.Path);
|
||||
|
||||
if (!pathsToWatch.Contains(parent))
|
||||
{
|
||||
pathsToWatch.Add(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string path in pathsToWatch)
|
||||
{
|
||||
FileSystemWatcher watcher = new FileSystemWatcher(path, "*");
|
||||
|
||||
watcher.IncludeSubdirectories = true;
|
||||
|
||||
watcher.Changed += watcher_Changed;
|
||||
|
||||
// All the others seem to trigger change events on the parent, so let's keep it simple for now.
|
||||
//watcher.Created += watcher_Changed;
|
||||
//watcher.Deleted += watcher_Changed;
|
||||
//watcher.Renamed += watcher_Changed;
|
||||
|
||||
watcher.EnableRaisingEvents = true;
|
||||
FileSystemWatchers.Add(watcher);
|
||||
}
|
||||
}
|
||||
|
||||
void watcher_Changed(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
if (!affectedPaths.Contains(e.FullPath))
|
||||
{
|
||||
affectedPaths.Add(e.FullPath);
|
||||
}
|
||||
|
||||
if (updateTimer == null)
|
||||
{
|
||||
updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(TimerDelayInSeconds), TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
updateTimer.Change(TimeSpan.FromSeconds(TimerDelayInSeconds), TimeSpan.FromMilliseconds(-1));
|
||||
}
|
||||
}
|
||||
|
||||
private void TimerStopped(object stateInfo)
|
||||
{
|
||||
updateTimer.Dispose();
|
||||
updateTimer = null;
|
||||
|
||||
List<string> paths = affectedPaths;
|
||||
affectedPaths = new List<string>();
|
||||
|
||||
ProcessPathChanges(paths);
|
||||
}
|
||||
|
||||
private void ProcessPathChanges(IEnumerable<string> paths)
|
||||
{
|
||||
List<BaseItem> itemsToRefresh = new List<BaseItem>();
|
||||
|
||||
foreach (BaseItem item in paths.Select(p => GetAffectedBaseItem(p)))
|
||||
{
|
||||
if (item != null && !itemsToRefresh.Contains(item))
|
||||
{
|
||||
itemsToRefresh.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsToRefresh.Any(i =>
|
||||
{
|
||||
var folder = i as Folder;
|
||||
|
||||
return folder != null && folder.IsRoot;
|
||||
}))
|
||||
{
|
||||
Kernel.Instance.ReloadRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
Parallel.For(0, itemsToRefresh.Count, i =>
|
||||
{
|
||||
Kernel.Instance.ReloadItem(itemsToRefresh[i]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private BaseItem GetAffectedBaseItem(string path)
|
||||
{
|
||||
BaseItem item = null;
|
||||
|
||||
while (item == null)
|
||||
{
|
||||
item = Kernel.Instance.RootFolder.FindByPath(path);
|
||||
|
||||
path = Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
foreach (FileSystemWatcher watcher in FileSystemWatchers)
|
||||
{
|
||||
watcher.Changed -= watcher_Changed;
|
||||
watcher.EnableRaisingEvents = false;
|
||||
watcher.Dispose();
|
||||
}
|
||||
|
||||
if (updateTimer != null)
|
||||
{
|
||||
updateTimer.Dispose();
|
||||
updateTimer = null;
|
||||
}
|
||||
|
||||
FileSystemWatchers.Clear();
|
||||
affectedPaths.Clear();
|
||||
}
|
||||
}
|
||||
}
|
182
MediaBrowser.Controller/IO/Shortcut.cs
Normal file
182
MediaBrowser.Controller/IO/Shortcut.cs
Normal file
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Controller.IO
|
||||
{
|
||||
public static class Shortcut
|
||||
{
|
||||
#region Signitures were imported from http://pinvoke.net
|
||||
[Flags()]
|
||||
enum SLGP_FLAGS
|
||||
{
|
||||
/// <summary>Retrieves the standard short (8.3 format) file name</summary>
|
||||
SLGP_SHORTPATH = 0x1,
|
||||
/// <summary>Retrieves the Universal Naming Convention (UNC) path name of the file</summary>
|
||||
SLGP_UNCPRIORITY = 0x2,
|
||||
/// <summary>Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded</summary>
|
||||
SLGP_RAWPATH = 0x4
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
struct WIN32_FIND_DATAW
|
||||
{
|
||||
public uint dwFileAttributes;
|
||||
public long ftCreationTime;
|
||||
public long ftLastAccessTime;
|
||||
public long ftLastWriteTime;
|
||||
public uint nFileSizeHigh;
|
||||
public uint nFileSizeLow;
|
||||
public uint dwReserved0;
|
||||
public uint dwReserved1;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
public string cFileName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
|
||||
public string cAlternateFileName;
|
||||
}
|
||||
|
||||
[Flags()]
|
||||
|
||||
enum SLR_FLAGS
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set,
|
||||
/// the high-order word of fFlags can be set to a time-out value that specifies the
|
||||
/// maximum amount of time to be spent resolving the link. The function returns if the
|
||||
/// link cannot be resolved within the time-out duration. If the high-order word is set
|
||||
/// to zero, the time-out duration will be set to the default value of 3,000 milliseconds
|
||||
/// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out
|
||||
/// duration, in milliseconds.
|
||||
/// </summary>
|
||||
SLR_NO_UI = 0x1,
|
||||
/// <summary>Obsolete and no longer used</summary>
|
||||
SLR_ANY_MATCH = 0x2,
|
||||
/// <summary>If the link object has changed, update its path and list of identifiers.
|
||||
/// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine
|
||||
/// whether or not the link object has changed.</summary>
|
||||
SLR_UPDATE = 0x4,
|
||||
/// <summary>Do not update the link information</summary>
|
||||
SLR_NOUPDATE = 0x8,
|
||||
/// <summary>Do not execute the search heuristics</summary>
|
||||
SLR_NOSEARCH = 0x10,
|
||||
/// <summary>Do not use distributed link tracking</summary>
|
||||
SLR_NOTRACK = 0x20,
|
||||
/// <summary>Disable distributed link tracking. By default, distributed link tracking tracks
|
||||
/// removable media across multiple devices based on the volume name. It also uses the
|
||||
/// Universal Naming Convention (UNC) path to track remote file systems whose drive letter
|
||||
/// has changed. Setting SLR_NOLINKINFO disables both types of tracking.</summary>
|
||||
SLR_NOLINKINFO = 0x40,
|
||||
/// <summary>Call the Microsoft Windows Installer</summary>
|
||||
SLR_INVOKE_MSI = 0x80
|
||||
}
|
||||
|
||||
|
||||
/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
|
||||
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
|
||||
interface IShellLinkW
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out IntPtr ppidl);
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(IntPtr pidl);
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
|
||||
int cchIconPath, out int piIcon);
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
|
||||
|
||||
}
|
||||
|
||||
[ComImport, Guid("0000010c-0000-0000-c000-000000000046"),
|
||||
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IPersist
|
||||
{
|
||||
[PreserveSig]
|
||||
void GetClassID(out Guid pClassID);
|
||||
}
|
||||
|
||||
|
||||
[ComImport, Guid("0000010b-0000-0000-C000-000000000046"),
|
||||
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IPersistFile : IPersist
|
||||
{
|
||||
new void GetClassID(out Guid pClassID);
|
||||
[PreserveSig]
|
||||
int IsDirty();
|
||||
|
||||
[PreserveSig]
|
||||
void Load([In, MarshalAs(UnmanagedType.LPWStr)]
|
||||
string pszFileName, uint dwMode);
|
||||
|
||||
[PreserveSig]
|
||||
void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
|
||||
[In, MarshalAs(UnmanagedType.Bool)] bool remember);
|
||||
|
||||
[PreserveSig]
|
||||
void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
|
||||
|
||||
[PreserveSig]
|
||||
void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName);
|
||||
}
|
||||
|
||||
const uint STGM_READ = 0;
|
||||
const int MAX_PATH = 260;
|
||||
|
||||
// CLSID_ShellLink from ShlGuid.h
|
||||
[
|
||||
ComImport(),
|
||||
Guid("00021401-0000-0000-C000-000000000046")
|
||||
]
|
||||
public class ShellLink
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static string ResolveShortcut(string filename)
|
||||
{
|
||||
ShellLink link = new ShellLink();
|
||||
((IPersistFile)link).Load(filename, STGM_READ);
|
||||
// TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files.
|
||||
// ((IShellLinkW)link).Resolve(hwnd, 0)
|
||||
StringBuilder sb = new StringBuilder(MAX_PATH);
|
||||
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
|
||||
((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static bool IsShortcut(string filename)
|
||||
{
|
||||
return Path.GetExtension(filename).EndsWith("lnk", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
258
MediaBrowser.Controller/Kernel.cs
Normal file
258
MediaBrowser.Controller/Kernel.cs
Normal file
|
@ -0,0 +1,258 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Json;
|
||||
using MediaBrowser.Common.Logging;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller
|
||||
{
|
||||
public class Kernel
|
||||
{
|
||||
public static Kernel Instance { get; private set; }
|
||||
|
||||
public string DataPath { get; private set; }
|
||||
|
||||
public HttpServer HttpServer { get; private set; }
|
||||
public ItemDataCache ItemDataCache { get; private set; }
|
||||
public ItemController ItemController { get; private set; }
|
||||
public UserController UserController { get; private set; }
|
||||
public PluginController PluginController { get; private set; }
|
||||
|
||||
public Configuration Configuration { get; private set; }
|
||||
public IEnumerable<IPlugin> Plugins { get; private set; }
|
||||
public IEnumerable<User> Users { get; private set; }
|
||||
public Folder RootFolder { get; private set; }
|
||||
|
||||
private DirectoryWatchers DirectoryWatchers { get; set; }
|
||||
|
||||
private string MediaRootFolderPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(DataPath, "Root");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a kernal based on a Data path, which is akin to our current programdata path
|
||||
/// </summary>
|
||||
public Kernel(string dataPath)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
DataPath = dataPath;
|
||||
|
||||
Logger.LoggerInstance = new FileLogger(Path.Combine(DataPath, "Logs"));
|
||||
|
||||
ItemController = new ItemController();
|
||||
UserController = new UserController(Path.Combine(DataPath, "Users"));
|
||||
PluginController = new PluginController(Path.Combine(DataPath, "Plugins"));
|
||||
DirectoryWatchers = new DirectoryWatchers();
|
||||
ItemDataCache = new ItemDataCache();
|
||||
|
||||
ItemController.PreBeginResolvePath += ItemController_PreBeginResolvePath;
|
||||
ItemController.BeginResolvePath += ItemController_BeginResolvePath;
|
||||
|
||||
// Add support for core media types - audio, video, etc
|
||||
AddBaseItemType<Folder, FolderResolver>();
|
||||
AddBaseItemType<Audio, AudioResolver>();
|
||||
AddBaseItemType<Video, VideoResolver>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the kernel to start spinning up
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
ReloadConfiguration();
|
||||
|
||||
ReloadHttpServer();
|
||||
|
||||
ReloadPlugins();
|
||||
|
||||
// Get users from users folder
|
||||
// Load root media folder
|
||||
Parallel.Invoke(ReloadUsers, ReloadRoot);
|
||||
var b = true;
|
||||
}
|
||||
|
||||
private void ReloadConfiguration()
|
||||
{
|
||||
// Deserialize config
|
||||
Configuration = GetConfiguration(DataPath);
|
||||
|
||||
Logger.LoggerInstance.LogSeverity = Configuration.LogSeverity;
|
||||
}
|
||||
|
||||
private void ReloadPlugins()
|
||||
{
|
||||
if (Plugins != null)
|
||||
{
|
||||
Parallel.For(0, Plugins.Count(), i =>
|
||||
{
|
||||
Plugins.ElementAt(i).Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
// Find plugins
|
||||
Plugins = PluginController.GetAllPlugins();
|
||||
|
||||
Parallel.For(0, Plugins.Count(), i =>
|
||||
{
|
||||
Plugins.ElementAt(i).Init();
|
||||
});
|
||||
}
|
||||
|
||||
private void ReloadHttpServer()
|
||||
{
|
||||
if (HttpServer != null)
|
||||
{
|
||||
HttpServer.Dispose();
|
||||
}
|
||||
|
||||
HttpServer = new HttpServer(Configuration.HttpServerPortNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new BaseItem subclass
|
||||
/// </summary>
|
||||
public void AddBaseItemType<TBaseItemType, TResolverType>()
|
||||
where TBaseItemType : BaseItem, new()
|
||||
where TResolverType : BaseItemResolver<TBaseItemType>, new()
|
||||
{
|
||||
ItemController.AddResovler<TBaseItemType, TResolverType>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a new BaseItem subclass
|
||||
/// </summary>
|
||||
public void RemoveBaseItemType<TBaseItemType, TResolverType>()
|
||||
where TBaseItemType : BaseItem, new()
|
||||
where TResolverType : BaseItemResolver<TBaseItemType>, new()
|
||||
{
|
||||
ItemController.RemoveResovler<TBaseItemType, TResolverType>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when a path is about to be resolved, but before child folders and files
|
||||
/// have been collected from the file system.
|
||||
/// This gives us a chance to cancel it if needed, resulting in the path being ignored
|
||||
/// </summary>
|
||||
void ItemController_PreBeginResolvePath(object sender, PreBeginResolveEventArgs e)
|
||||
{
|
||||
if (e.IsHidden || e.IsSystemFile)
|
||||
{
|
||||
// Ignore hidden files and folders
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
else if (Path.GetFileName(e.Path).Equals("trailers", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Ignore any folders named "trailers"
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when a path is about to be resolved, but after child folders and files
|
||||
/// This gives us a chance to cancel it if needed, resulting in the path being ignored
|
||||
/// </summary>
|
||||
void ItemController_BeginResolvePath(object sender, ItemResolveEventArgs e)
|
||||
{
|
||||
if (e.IsFolder)
|
||||
{
|
||||
if (e.ContainsFile(".ignore"))
|
||||
{
|
||||
// Ignore any folders containing a file called .ignore
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReloadUsers()
|
||||
{
|
||||
Users = UserController.GetAllUsers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the root media folder
|
||||
/// </summary>
|
||||
public void ReloadRoot()
|
||||
{
|
||||
if (!Directory.Exists(MediaRootFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(MediaRootFolderPath);
|
||||
}
|
||||
|
||||
DirectoryWatchers.Stop();
|
||||
|
||||
RootFolder = ItemController.GetItem(MediaRootFolderPath) as Folder;
|
||||
|
||||
DirectoryWatchers.Start();
|
||||
}
|
||||
|
||||
private static MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();
|
||||
public static Guid GetMD5(string str)
|
||||
{
|
||||
lock (md5Provider)
|
||||
{
|
||||
return new Guid(md5Provider.ComputeHash(Encoding.Unicode.GetBytes(str)));
|
||||
}
|
||||
}
|
||||
|
||||
private static Configuration GetConfiguration(string directory)
|
||||
{
|
||||
string file = Path.Combine(directory, "config.js");
|
||||
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
return new Configuration();
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<Configuration>(file);
|
||||
}
|
||||
|
||||
public void ReloadItem(BaseItem item)
|
||||
{
|
||||
Folder folder = item as Folder;
|
||||
|
||||
if (folder != null && folder.IsRoot)
|
||||
{
|
||||
ReloadRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Directory.Exists(item.Path) && !File.Exists(item.Path))
|
||||
{
|
||||
ReloadItem(item.Parent);
|
||||
return;
|
||||
}
|
||||
|
||||
BaseItem newItem = ItemController.GetItem(item.Parent, item.Path);
|
||||
|
||||
List<BaseItem> children = item.Parent.Children.ToList();
|
||||
|
||||
int index = children.IndexOf(item);
|
||||
|
||||
children.RemoveAt(index);
|
||||
|
||||
children.Insert(index, newItem);
|
||||
|
||||
item.Parent.Children = children.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
326
MediaBrowser.Controller/Library/ItemController.cs
Normal file
326
MediaBrowser.Controller/Library/ItemController.cs
Normal file
|
@ -0,0 +1,326 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
public class ItemController
|
||||
{
|
||||
private List<IBaseItemResolver> Resolvers = new List<IBaseItemResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new BaseItem resolver.
|
||||
/// </summary>
|
||||
public void AddResovler<TBaseItemType, TResolverType>()
|
||||
where TBaseItemType : BaseItem, new()
|
||||
where TResolverType : BaseItemResolver<TBaseItemType>, new()
|
||||
{
|
||||
Resolvers.Insert(0, new TResolverType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new BaseItem resolver.
|
||||
/// </summary>
|
||||
public void RemoveResovler<TBaseItemType, TResolverType>()
|
||||
where TBaseItemType : BaseItem, new()
|
||||
where TResolverType : BaseItemResolver<TBaseItemType>, new()
|
||||
{
|
||||
IBaseItemResolver resolver = Resolvers.First(r => r.GetType() == typeof(TResolverType));
|
||||
|
||||
Resolvers.Remove(resolver);
|
||||
}
|
||||
|
||||
#region PreBeginResolvePath Event
|
||||
/// <summary>
|
||||
/// Fires when a path is about to be resolved, but before child folders and files
|
||||
/// have been collected from the file system.
|
||||
/// This gives listeners a chance to cancel the operation and cause the path to be ignored.
|
||||
/// </summary>
|
||||
public event EventHandler<PreBeginResolveEventArgs> PreBeginResolvePath;
|
||||
private bool OnPreBeginResolvePath(Folder parent, string path, FileAttributes attributes)
|
||||
{
|
||||
PreBeginResolveEventArgs args = new PreBeginResolveEventArgs()
|
||||
{
|
||||
Path = path,
|
||||
Parent = parent,
|
||||
FileAttributes = attributes,
|
||||
Cancel = false
|
||||
};
|
||||
|
||||
if (PreBeginResolvePath != null)
|
||||
{
|
||||
PreBeginResolvePath(this, args);
|
||||
}
|
||||
|
||||
return !args.Cancel;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BeginResolvePath Event
|
||||
/// <summary>
|
||||
/// Fires when a path is about to be resolved, but after child folders and files
|
||||
/// have been collected from the file system.
|
||||
/// This gives listeners a chance to cancel the operation and cause the path to be ignored.
|
||||
/// </summary>
|
||||
public event EventHandler<ItemResolveEventArgs> BeginResolvePath;
|
||||
private bool OnBeginResolvePath(ItemResolveEventArgs args)
|
||||
{
|
||||
if (BeginResolvePath != null)
|
||||
{
|
||||
BeginResolvePath(this, args);
|
||||
}
|
||||
|
||||
return !args.Cancel;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Item Events
|
||||
/// <summary>
|
||||
/// Called when an item is being created.
|
||||
/// This should be used to fill item values, such as metadata
|
||||
/// </summary>
|
||||
public event EventHandler<GenericItemEventArgs<BaseItem>> ItemCreating;
|
||||
|
||||
/// <summary>
|
||||
/// Called when an item has been created.
|
||||
/// This should be used to process or modify item values.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericItemEventArgs<BaseItem>> ItemCreated;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Called when an item has been created
|
||||
/// </summary>
|
||||
private void OnItemCreated(BaseItem item, Folder parent)
|
||||
{
|
||||
GenericItemEventArgs<BaseItem> args = new GenericItemEventArgs<BaseItem> { Item = item };
|
||||
|
||||
if (ItemCreating != null)
|
||||
{
|
||||
ItemCreating(this, args);
|
||||
}
|
||||
|
||||
if (ItemCreated != null)
|
||||
{
|
||||
ItemCreated(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void FireCreateEventsRecursive(Folder folder, Folder parent)
|
||||
{
|
||||
OnItemCreated(folder, parent);
|
||||
|
||||
int count = folder.Children.Length;
|
||||
|
||||
Parallel.For(0, count, i =>
|
||||
{
|
||||
BaseItem item = folder.Children[i];
|
||||
|
||||
Folder childFolder = item as Folder;
|
||||
|
||||
if (childFolder != null)
|
||||
{
|
||||
FireCreateEventsRecursive(childFolder, folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnItemCreated(item, folder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private BaseItem ResolveItem(ItemResolveEventArgs args)
|
||||
{
|
||||
// If that didn't pan out, try the slow ones
|
||||
foreach (IBaseItemResolver resolver in Resolvers)
|
||||
{
|
||||
var item = resolver.ResolvePath(args);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a path into a BaseItem
|
||||
/// </summary>
|
||||
public BaseItem GetItem(string path)
|
||||
{
|
||||
return GetItem(null, path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a path into a BaseItem
|
||||
/// </summary>
|
||||
public BaseItem GetItem(Folder parent, string path)
|
||||
{
|
||||
BaseItem item = GetItemInternal(parent, path, File.GetAttributes(path));
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
var folder = item as Folder;
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
FireCreateEventsRecursive(folder, parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnItemCreated(item, parent);
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a path into a BaseItem
|
||||
/// </summary>
|
||||
private BaseItem GetItemInternal(Folder parent, string path, FileAttributes attributes)
|
||||
{
|
||||
if (!OnPreBeginResolvePath(parent, path, attributes))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerable<KeyValuePair<string, FileAttributes>> fileSystemChildren;
|
||||
|
||||
// Gather child folder and files
|
||||
if (attributes.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
fileSystemChildren = Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly).Select(f => new KeyValuePair<string, FileAttributes>(f, File.GetAttributes(f)));
|
||||
|
||||
bool isVirtualFolder = parent != null && parent.IsRoot;
|
||||
fileSystemChildren = FilterChildFileSystemEntries(fileSystemChildren, isVirtualFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSystemChildren = new KeyValuePair<string, FileAttributes>[] { };
|
||||
}
|
||||
|
||||
ItemResolveEventArgs args = new ItemResolveEventArgs()
|
||||
{
|
||||
Path = path,
|
||||
FileAttributes = attributes,
|
||||
FileSystemChildren = fileSystemChildren,
|
||||
Parent = parent,
|
||||
Cancel = false
|
||||
};
|
||||
|
||||
// Fire BeginResolvePath to see if anyone wants to cancel this operation
|
||||
if (!OnBeginResolvePath(args))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
BaseItem item = ResolveItem(args);
|
||||
|
||||
var folder = item as Folder;
|
||||
|
||||
if (folder != null)
|
||||
{
|
||||
// If it's a folder look for child entities
|
||||
AttachChildren(folder, fileSystemChildren);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds child BaseItems for a given Folder
|
||||
/// </summary>
|
||||
private void AttachChildren(Folder folder, IEnumerable<KeyValuePair<string, FileAttributes>> fileSystemChildren)
|
||||
{
|
||||
List<BaseItem> baseItemChildren = new List<BaseItem>();
|
||||
|
||||
int count = fileSystemChildren.Count();
|
||||
|
||||
// Resolve the child folder paths into entities
|
||||
Parallel.For(0, count, i =>
|
||||
{
|
||||
KeyValuePair<string, FileAttributes> child = fileSystemChildren.ElementAt(i);
|
||||
|
||||
BaseItem item = GetItemInternal(folder, child.Key, child.Value);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
lock (baseItemChildren)
|
||||
{
|
||||
baseItemChildren.Add(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Sort them
|
||||
folder.Children = baseItemChildren.OrderBy(f =>
|
||||
{
|
||||
return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName;
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms shortcuts into their actual paths
|
||||
/// </summary>
|
||||
private List<KeyValuePair<string, FileAttributes>> FilterChildFileSystemEntries(IEnumerable<KeyValuePair<string, FileAttributes>> fileSystemChildren, bool flattenShortcuts)
|
||||
{
|
||||
List<KeyValuePair<string, FileAttributes>> returnFiles = new List<KeyValuePair<string, FileAttributes>>();
|
||||
|
||||
// Loop through each file
|
||||
foreach (KeyValuePair<string, FileAttributes> file in fileSystemChildren)
|
||||
{
|
||||
// Folders
|
||||
if (file.Value.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
returnFiles.Add(file);
|
||||
}
|
||||
|
||||
// If it's a shortcut, resolve it
|
||||
else if (Shortcut.IsShortcut(file.Key))
|
||||
{
|
||||
string newPath = Shortcut.ResolveShortcut(file.Key);
|
||||
FileAttributes newPathAttributes = File.GetAttributes(newPath);
|
||||
|
||||
// Find out if the shortcut is pointing to a directory or file
|
||||
|
||||
if (newPathAttributes.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
// If we're flattening then get the shortcut's children
|
||||
|
||||
if (flattenShortcuts)
|
||||
{
|
||||
IEnumerable<KeyValuePair<string, FileAttributes>> newChildren = Directory.GetFileSystemEntries(newPath, "*", SearchOption.TopDirectoryOnly).Select(f => new KeyValuePair<string, FileAttributes>(f, File.GetAttributes(f)));
|
||||
|
||||
returnFiles.AddRange(FilterChildFileSystemEntries(newChildren, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
returnFiles.Add(new KeyValuePair<string, FileAttributes>(newPath, newPathAttributes));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
returnFiles.Add(new KeyValuePair<string, FileAttributes>(newPath, newPathAttributes));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
returnFiles.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
return returnFiles;
|
||||
}
|
||||
}
|
||||
}
|
32
MediaBrowser.Controller/Library/ItemDataCache.cs
Normal file
32
MediaBrowser.Controller/Library/ItemDataCache.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
public class ItemDataCache
|
||||
{
|
||||
private Dictionary<string, object> Data = new Dictionary<string, object>();
|
||||
|
||||
public void SetValue<T>(BaseItem item, string propertyName, T value)
|
||||
{
|
||||
Data[GetKey(item, propertyName)] = value;
|
||||
}
|
||||
|
||||
public T GetValue<T>(BaseItem item, string propertyName)
|
||||
{
|
||||
string key = GetKey(item, propertyName);
|
||||
|
||||
if (Data.ContainsKey(key))
|
||||
{
|
||||
return (T)Data[key];
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
private string GetKey(BaseItem item, string propertyName)
|
||||
{
|
||||
return item.Id.ToString() + "-" + propertyName;
|
||||
}
|
||||
}
|
||||
}
|
92
MediaBrowser.Controller/MediaBrowser.Controller.csproj
Normal file
92
MediaBrowser.Controller/MediaBrowser.Controller.csproj
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Controller</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Controller</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Reactive">
|
||||
<HintPath>..\packages\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Events\ItemResolveEventArgs.cs" />
|
||||
<Compile Include="IO\DirectoryWatchers.cs" />
|
||||
<Compile Include="IO\Shortcut.cs" />
|
||||
<Compile Include="Library\ItemController.cs" />
|
||||
<Compile Include="Kernel.cs" />
|
||||
<Compile Include="Library\ItemDataCache.cs" />
|
||||
<Compile Include="Net\CollectionExtensions.cs" />
|
||||
<Compile Include="Net\HttpServer.cs" />
|
||||
<Compile Include="Net\Request.cs" />
|
||||
<Compile Include="Net\RequestContext.cs" />
|
||||
<Compile Include="Net\Response.cs" />
|
||||
<Compile Include="Net\StreamExtensions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Resolvers\AudioResolver.cs" />
|
||||
<Compile Include="Resolvers\BaseItemResolver.cs" />
|
||||
<Compile Include="Resolvers\FolderResolver.cs" />
|
||||
<Compile Include="Resolvers\VideoResolver.cs" />
|
||||
<Compile Include="UserController.cs" />
|
||||
<Compile Include="Xml\BaseItemXmlParser.cs" />
|
||||
<Compile Include="Xml\FolderXmlParser.cs" />
|
||||
<Compile Include="Xml\XmlExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
14
MediaBrowser.Controller/Net/CollectionExtensions.cs
Normal file
14
MediaBrowser.Controller/Net/CollectionExtensions.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public static class CollectionExtensions
|
||||
{
|
||||
public static IDictionary<string, IEnumerable<string>> ToDictionary(this NameValueCollection source)
|
||||
{
|
||||
return source.AllKeys.ToDictionary<string, string, IEnumerable<string>>(key => key, source.GetValues);
|
||||
}
|
||||
}
|
||||
}
|
47
MediaBrowser.Controller/Net/HttpServer.cs
Normal file
47
MediaBrowser.Controller/Net/HttpServer.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class HttpServer : IObservable<RequestContext>, IDisposable
|
||||
{
|
||||
private readonly HttpListener listener;
|
||||
private readonly IObservable<RequestContext> stream;
|
||||
|
||||
public HttpServer(int port)
|
||||
: this("http://+:" + port + "/")
|
||||
{
|
||||
}
|
||||
|
||||
public HttpServer(string url)
|
||||
{
|
||||
listener = new HttpListener();
|
||||
listener.Prefixes.Add(url);
|
||||
listener.Start();
|
||||
stream = ObservableHttpContext();
|
||||
}
|
||||
|
||||
private IObservable<RequestContext> ObservableHttpContext()
|
||||
{
|
||||
return Observable.Create<RequestContext>(obs =>
|
||||
Observable.FromAsyncPattern<HttpListenerContext>(listener.BeginGetContext,
|
||||
listener.EndGetContext)()
|
||||
.Select(c => new RequestContext(c))
|
||||
.Subscribe(obs))
|
||||
.Repeat()
|
||||
.Retry()
|
||||
.Publish()
|
||||
.RefCount();
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
listener.Stop();
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<RequestContext> observer)
|
||||
{
|
||||
return stream.Subscribe(observer);
|
||||
}
|
||||
}
|
||||
}
|
18
MediaBrowser.Controller/Net/Request.cs
Normal file
18
MediaBrowser.Controller/Net/Request.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class Request
|
||||
{
|
||||
public string HttpMethod { get; set; }
|
||||
public IDictionary<string, IEnumerable<string>> Headers { get; set; }
|
||||
public Stream InputStream { get; set; }
|
||||
public string RawUrl { get; set; }
|
||||
public int ContentLength
|
||||
{
|
||||
get { return int.Parse(Headers["Content-Length"].First()); }
|
||||
}
|
||||
}
|
||||
}
|
37
MediaBrowser.Controller/Net/RequestContext.cs
Normal file
37
MediaBrowser.Controller/Net/RequestContext.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class RequestContext
|
||||
{
|
||||
public HttpListenerRequest Request { get; private set; }
|
||||
public HttpListenerResponse Response { get; private set; }
|
||||
|
||||
public RequestContext(HttpListenerContext context)
|
||||
{
|
||||
Response = context.Response;
|
||||
Request = context.Request;
|
||||
}
|
||||
|
||||
public void Respond(Response response)
|
||||
{
|
||||
Response.AddHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
foreach (var header in response.Headers)
|
||||
{
|
||||
Response.AddHeader(header.Key, header.Value);
|
||||
}
|
||||
|
||||
Response.ContentType = response.ContentType;
|
||||
Response.StatusCode = response.StatusCode;
|
||||
|
||||
Response.SendChunked = true;
|
||||
|
||||
GZipStream gzipStream = new GZipStream(Response.OutputStream, CompressionMode.Compress, false);
|
||||
|
||||
response.WriteStream(Response.OutputStream);
|
||||
}
|
||||
}
|
||||
}
|
49
MediaBrowser.Controller/Net/Response.cs
Normal file
49
MediaBrowser.Controller/Net/Response.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class Response
|
||||
{
|
||||
protected RequestContext RequestContext { get; private set; }
|
||||
|
||||
public Response(RequestContext ctx)
|
||||
{
|
||||
RequestContext = ctx;
|
||||
|
||||
WriteStream = s => { };
|
||||
StatusCode = 200;
|
||||
Headers = new Dictionary<string, string>();
|
||||
CacheDuration = TimeSpan.FromTicks(0);
|
||||
ContentType = "text/html";
|
||||
}
|
||||
|
||||
public int StatusCode { get; set; }
|
||||
public string ContentType { get; set; }
|
||||
public IDictionary<string, string> Headers { get; set; }
|
||||
public TimeSpan CacheDuration { get; set; }
|
||||
public Action<Stream> WriteStream { get; set; }
|
||||
}
|
||||
|
||||
/*public class ByteResponse : Response
|
||||
{
|
||||
public ByteResponse(byte[] bytes)
|
||||
{
|
||||
WriteStream = async s =>
|
||||
{
|
||||
await s.WriteAsync(bytes, 0, bytes.Length);
|
||||
s.Close();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class StringResponse : ByteResponse
|
||||
{
|
||||
public StringResponse(string message)
|
||||
: base(Encoding.UTF8.GetBytes(message))
|
||||
{
|
||||
}
|
||||
}*/
|
||||
}
|
20
MediaBrowser.Controller/Net/StreamExtensions.cs
Normal file
20
MediaBrowser.Controller/Net/StreamExtensions.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static IObservable<byte[]> ReadBytes(this Stream stream, int count)
|
||||
{
|
||||
var buffer = new byte[count];
|
||||
return Observable.FromAsyncPattern((cb, state) => stream.BeginRead(buffer, 0, count, cb, state), ar =>
|
||||
{
|
||||
stream.EndRead(ar);
|
||||
return buffer;
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Controller/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Controller/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Controller")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Controller")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("bc09905a-04ed-497d-b39b-27593401e715")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
44
MediaBrowser.Controller/Resolvers/AudioResolver.cs
Normal file
44
MediaBrowser.Controller/Resolvers/AudioResolver.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using System.IO;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Resolvers
|
||||
{
|
||||
public class AudioResolver : BaseItemResolver<Audio>
|
||||
{
|
||||
protected override Audio Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (!args.IsFolder)
|
||||
{
|
||||
if (IsAudioFile(args.Path))
|
||||
{
|
||||
return new Audio();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsAudioFile(string path)
|
||||
{
|
||||
string extension = Path.GetExtension(path).ToLower();
|
||||
|
||||
switch (extension)
|
||||
{
|
||||
case ".mp3":
|
||||
case ".wma":
|
||||
case ".acc":
|
||||
case ".flac":
|
||||
case ".m4a":
|
||||
case ".m4b":
|
||||
case ".wav":
|
||||
case ".ape":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
146
MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
Normal file
146
MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
Normal file
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Resolvers
|
||||
{
|
||||
public abstract class BaseItemResolver<T> : IBaseItemResolver
|
||||
where T : BaseItem, new ()
|
||||
{
|
||||
protected virtual T Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual void SetItemValues(T item, ItemResolveEventArgs args)
|
||||
{
|
||||
// If the subclass didn't specify this
|
||||
if (string.IsNullOrEmpty(item.Path))
|
||||
{
|
||||
item.Path = args.Path;
|
||||
}
|
||||
|
||||
Folder parentFolder = args.Parent as Folder;
|
||||
|
||||
if (parentFolder != null)
|
||||
{
|
||||
item.Parent = parentFolder;
|
||||
}
|
||||
|
||||
item.Id = Kernel.GetMD5(item.Path);
|
||||
|
||||
PopulateImages(item, args);
|
||||
PopulateLocalTrailers(item, args);
|
||||
}
|
||||
|
||||
public BaseItem ResolvePath(ItemResolveEventArgs args)
|
||||
{
|
||||
T item = Resolve(args);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
SetItemValues(item, args);
|
||||
|
||||
EnsureName(item);
|
||||
EnsureDates(item);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void EnsureName(T item)
|
||||
{
|
||||
// If the subclass didn't supply a name, add it here
|
||||
if (string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
item.Name = Path.GetFileNameWithoutExtension(item.Path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void EnsureDates(T item)
|
||||
{
|
||||
// If the subclass didn't supply dates, add them here
|
||||
if (item.DateCreated == DateTime.MinValue)
|
||||
{
|
||||
item.DateCreated = Path.IsPathRooted(item.Path) ? File.GetCreationTime(item.Path) : DateTime.Now;
|
||||
}
|
||||
|
||||
if (item.DateModified == DateTime.MinValue)
|
||||
{
|
||||
item.DateModified = Path.IsPathRooted(item.Path) ? File.GetLastWriteTime(item.Path) : DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PopulateImages(T item, ItemResolveEventArgs args)
|
||||
{
|
||||
List<string> backdropFiles = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string,FileAttributes> file in args.FileSystemChildren)
|
||||
{
|
||||
if (file.Value.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string filePath = file.Key;
|
||||
|
||||
string ext = Path.GetExtension(filePath);
|
||||
|
||||
if (!ext.EndsWith("png", StringComparison.OrdinalIgnoreCase) && !ext.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = Path.GetFileNameWithoutExtension(filePath);
|
||||
|
||||
if (name.Equals("folder", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.PrimaryImagePath = filePath;
|
||||
}
|
||||
else if (name.StartsWith("backdrop", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
backdropFiles.Add(filePath);
|
||||
}
|
||||
if (name.Equals("logo", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.LogoImagePath = filePath;
|
||||
}
|
||||
if (name.Equals("banner", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.BannerImagePath = filePath;
|
||||
}
|
||||
if (name.Equals("art", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ArtImagePath = filePath;
|
||||
}
|
||||
if (name.Equals("thumb", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ThumbnailImagePath = filePath;
|
||||
}
|
||||
}
|
||||
|
||||
item.BackdropImagePaths = backdropFiles;
|
||||
}
|
||||
|
||||
protected virtual void PopulateLocalTrailers(T item, ItemResolveEventArgs args)
|
||||
{
|
||||
var trailerPath = args.GetFolderByName("trailers");
|
||||
|
||||
if (trailerPath.HasValue)
|
||||
{
|
||||
string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
item.LocalTrailers = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(f)).OfType<Video>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBaseItemResolver
|
||||
{
|
||||
BaseItem ResolvePath(ItemResolveEventArgs args);
|
||||
}
|
||||
}
|
45
MediaBrowser.Controller/Resolvers/FolderResolver.cs
Normal file
45
MediaBrowser.Controller/Resolvers/FolderResolver.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Controller.Xml;
|
||||
|
||||
namespace MediaBrowser.Controller.Resolvers
|
||||
{
|
||||
public class FolderResolver : BaseFolderResolver<Folder>
|
||||
{
|
||||
protected override Folder Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.IsFolder)
|
||||
{
|
||||
return new Folder();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BaseFolderResolver<T> : BaseItemResolver<T>
|
||||
where T : Folder, new ()
|
||||
{
|
||||
protected override void SetItemValues(T item, ItemResolveEventArgs args)
|
||||
{
|
||||
base.SetItemValues(item, args);
|
||||
|
||||
item.IsRoot = args.Parent == null;
|
||||
|
||||
PopulateFolderMetadata(item, args);
|
||||
}
|
||||
|
||||
private void PopulateFolderMetadata(Folder folder, ItemResolveEventArgs args)
|
||||
{
|
||||
var metadataFile = args.GetFileByName("folder.xml");
|
||||
|
||||
if (metadataFile.HasValue)
|
||||
{
|
||||
new FolderXmlParser().Fetch(folder, metadataFile.Value.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
MediaBrowser.Controller/Resolvers/VideoResolver.cs
Normal file
114
MediaBrowser.Controller/Resolvers/VideoResolver.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using System.IO;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Resolvers
|
||||
{
|
||||
public class VideoResolver : BaseVideoResolver<Video>
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class BaseVideoResolver<T> : BaseItemResolver<T>
|
||||
where T : Video, new()
|
||||
{
|
||||
protected override T Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (!args.IsFolder)
|
||||
{
|
||||
if (IsVideoFile(args.Path))
|
||||
{
|
||||
return new T()
|
||||
{
|
||||
VideoType = VideoType.VideoFile,
|
||||
Path = args.Path
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
T item = ResolveFromFolderName(args.Path);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, FileAttributes> folder in args.FileSystemChildren)
|
||||
{
|
||||
if (!folder.Value.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item = ResolveFromFolderName(folder.Key);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private T ResolveFromFolderName(string folder)
|
||||
{
|
||||
if (folder.IndexOf("video_ts", System.StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return new T()
|
||||
{
|
||||
VideoType = VideoType.DVD,
|
||||
Path = Path.GetDirectoryName(folder)
|
||||
};
|
||||
}
|
||||
if (folder.IndexOf("bdmv", System.StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return new T()
|
||||
{
|
||||
VideoType = VideoType.BluRay,
|
||||
Path = Path.GetDirectoryName(folder)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsVideoFile(string path)
|
||||
{
|
||||
string extension = Path.GetExtension(path).ToLower();
|
||||
|
||||
switch (extension)
|
||||
{
|
||||
case ".mkv":
|
||||
case ".m2ts":
|
||||
case ".iso":
|
||||
case ".ts":
|
||||
case ".rmvb":
|
||||
case ".mov":
|
||||
case ".avi":
|
||||
case ".mpg":
|
||||
case ".mpeg":
|
||||
case ".wmv":
|
||||
case ".mp4":
|
||||
case ".divx":
|
||||
case ".dvr-ms":
|
||||
case ".wtv":
|
||||
case ".ogm":
|
||||
case ".ogv":
|
||||
case ".asf":
|
||||
case ".m4v":
|
||||
case ".flv":
|
||||
case ".f4v":
|
||||
case ".3gp":
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
MediaBrowser.Controller/UserController.cs
Normal file
60
MediaBrowser.Controller/UserController.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common.Json;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
||||
namespace MediaBrowser.Controller
|
||||
{
|
||||
public class UserController
|
||||
{
|
||||
public string UsersPath { get; set; }
|
||||
|
||||
public UserController(string usersPath)
|
||||
{
|
||||
UsersPath = usersPath;
|
||||
}
|
||||
|
||||
public IEnumerable<User> GetAllUsers()
|
||||
{
|
||||
if (!Directory.Exists(UsersPath))
|
||||
{
|
||||
Directory.CreateDirectory(UsersPath);
|
||||
}
|
||||
|
||||
List<User> list = new List<User>();
|
||||
|
||||
foreach (string folder in Directory.GetDirectories(UsersPath, "*", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
User item = GetFromDirectory(folder);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private User GetFromDirectory(string path)
|
||||
{
|
||||
string file = Path.Combine(path, "user.js");
|
||||
|
||||
return JsonSerializer.Deserialize<User>(file);
|
||||
}
|
||||
|
||||
public void CreateUser(User user)
|
||||
{
|
||||
user.Id = Guid.NewGuid();
|
||||
|
||||
user.DateCreated = user.DateModified = DateTime.Now;
|
||||
|
||||
string userFolder = Path.Combine(UsersPath, user.Id.ToString());
|
||||
|
||||
Directory.CreateDirectory(userFolder);
|
||||
|
||||
JsonSerializer.Serialize(user, Path.Combine(userFolder, "user.js"));
|
||||
}
|
||||
}
|
||||
}
|
591
MediaBrowser.Controller/Xml/BaseItemXmlParser.cs
Normal file
591
MediaBrowser.Controller/Xml/BaseItemXmlParser.cs
Normal file
|
@ -0,0 +1,591 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Xml
|
||||
{
|
||||
public class BaseItemXmlParser<T>
|
||||
where T : BaseItem, new()
|
||||
{
|
||||
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)
|
||||
{
|
||||
FetchDataFromXmlNode(node, item);
|
||||
}
|
||||
|
||||
// If dates weren't supplied in metadata, use values from the file
|
||||
if (item.DateCreated == DateTime.MinValue)
|
||||
{
|
||||
item.DateCreated = File.GetCreationTime(metadataFile);
|
||||
}
|
||||
|
||||
if (item.DateModified == DateTime.MinValue)
|
||||
{
|
||||
item.DateModified = File.GetLastWriteTime(metadataFile);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FetchDataFromXmlNode(XmlNode node, T item)
|
||||
{
|
||||
switch (node.Name)
|
||||
{
|
||||
case "Added":
|
||||
DateTime added;
|
||||
if (DateTime.TryParse(node.InnerText ?? string.Empty, out added))
|
||||
{
|
||||
item.DateCreated = added;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Type":
|
||||
{
|
||||
item.DisplayMediaType = node.InnerText ?? string.Empty;
|
||||
|
||||
switch (item.DisplayMediaType.ToLower())
|
||||
{
|
||||
case "blu-ray":
|
||||
item.DisplayMediaType = VideoType.BluRay.ToString();
|
||||
break;
|
||||
case "dvd":
|
||||
item.DisplayMediaType = VideoType.DVD.ToString();
|
||||
break;
|
||||
case "":
|
||||
item.DisplayMediaType = null;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "banner":
|
||||
item.BannerImagePath = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "LocalTitle":
|
||||
item.Name = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "SortTitle":
|
||||
item.SortName = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Overview":
|
||||
case "Description":
|
||||
item.Overview = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "TagLine":
|
||||
item.Tagline = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "ContentRating":
|
||||
case "MPAARating":
|
||||
item.OfficialRating = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "CustomRating":
|
||||
item.CustomRating = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "CustomPin":
|
||||
item.CustomPin = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Covers":
|
||||
FetchFromCoversNode(node, item);
|
||||
break;
|
||||
|
||||
case "Genres":
|
||||
FetchFromGenresNode(node, item);
|
||||
break;
|
||||
|
||||
case "Genre":
|
||||
{
|
||||
var genres = (item.Genres ?? new string[] { }).ToList();
|
||||
genres.AddRange(GetSplitValues(node.InnerText, '|'));
|
||||
|
||||
item.Genres = genres;
|
||||
break;
|
||||
}
|
||||
|
||||
case "AspectRatio":
|
||||
item.AspectRatio = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Rating":
|
||||
case "IMDBrating":
|
||||
float IMDBrating = node.SafeGetSingle((float)-1, (float)10);
|
||||
|
||||
if (IMDBrating >= 0)
|
||||
{
|
||||
item.UserRating = IMDBrating;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Network":
|
||||
{
|
||||
var studios = (item.Studios ?? new string[] { }).ToList();
|
||||
studios.AddRange(GetSplitValues(node.InnerText, '|'));
|
||||
|
||||
item.Studios = studios;
|
||||
break;
|
||||
}
|
||||
case "Studios":
|
||||
FetchFromStudiosNode(node, item);
|
||||
break;
|
||||
|
||||
case "Director":
|
||||
{
|
||||
var list = (item.People ?? new Person[]{}).ToList();
|
||||
list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new Person() { Name = v, PersonType = PersonType.Director }));
|
||||
|
||||
item.People = list;
|
||||
break;
|
||||
}
|
||||
case "Writer":
|
||||
{
|
||||
var list = (item.People ?? new Person[] { }).ToList();
|
||||
list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new Person() { Name = v, PersonType = PersonType.Writer }));
|
||||
|
||||
item.People = list;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Actors":
|
||||
case "GuestStars":
|
||||
{
|
||||
var list = (item.People ?? new Person[] { }).ToList();
|
||||
list.AddRange(GetSplitValues(node.InnerText, '|').Select(v => new Person() { Name = v, PersonType = PersonType.Actor }));
|
||||
|
||||
item.People = list;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Persons":
|
||||
FetchDataFromPersonsNode(node, item);
|
||||
break;
|
||||
|
||||
case "Trailer":
|
||||
item.TrailerUrl = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "ParentalRating":
|
||||
FetchFromParentalRatingNode(node, item);
|
||||
break;
|
||||
|
||||
case "ProductionYear":
|
||||
{
|
||||
int ProductionYear;
|
||||
if (int.TryParse(node.InnerText, out ProductionYear) && ProductionYear > 1850)
|
||||
{
|
||||
item.ProductionYear = ProductionYear;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "MediaInfo":
|
||||
FetchMediaInfo(node, item);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FetchFromCoversNode(XmlNode node, T item)
|
||||
{
|
||||
string cover = node.SafeGetString("Front");
|
||||
|
||||
if (!string.IsNullOrEmpty(cover))
|
||||
{
|
||||
item.PrimaryImagePath = cover;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FetchMediaInfo(XmlNode node, T item)
|
||||
{
|
||||
var iMediaInfo = item as Video;
|
||||
|
||||
if (iMediaInfo != null)
|
||||
{
|
||||
FetchMediaInfo(node, iMediaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FetchMediaInfo(XmlNode node, Video item)
|
||||
{
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Audio":
|
||||
{
|
||||
AudioStream stream = FetchMediaInfoAudio(childNode);
|
||||
|
||||
List<AudioStream> streams = item.AudioStreams.ToList();
|
||||
streams.Add(stream);
|
||||
item.AudioStreams = streams;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "Video":
|
||||
FetchMediaInfoVideo(childNode, item);
|
||||
break;
|
||||
|
||||
case "Subtitle":
|
||||
FetchMediaInfoSubtitles(childNode, item);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual AudioStream FetchMediaInfoAudio(XmlNode node)
|
||||
{
|
||||
AudioStream stream = new AudioStream();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "BitRate":
|
||||
stream.BitRate = childNode.SafeGetInt32();
|
||||
break;
|
||||
|
||||
case "Channels":
|
||||
stream.Channels = childNode.SafeGetInt32();
|
||||
break;
|
||||
|
||||
case "Language":
|
||||
stream.Language = childNode.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Codec":
|
||||
{
|
||||
string codec = childNode.InnerText ?? 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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
protected virtual void FetchMediaInfoVideo(XmlNode node, Video item)
|
||||
{
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Width":
|
||||
item.Width = childNode.SafeGetInt32();
|
||||
break;
|
||||
|
||||
case "Height":
|
||||
item.Height = childNode.SafeGetInt32();
|
||||
break;
|
||||
|
||||
case "BitRate":
|
||||
item.VideoBitRate = childNode.SafeGetInt32();
|
||||
break;
|
||||
|
||||
case "FrameRate":
|
||||
item.FrameRate = childNode.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "ScanType":
|
||||
item.ScanType = childNode.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Duration":
|
||||
item.RunTime = TimeSpan.FromMinutes(childNode.SafeGetInt32());
|
||||
break;
|
||||
|
||||
case "DurationSeconds":
|
||||
int seconds = childNode.SafeGetInt32();
|
||||
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.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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FetchMediaInfoSubtitles(XmlNode node, Video item)
|
||||
{
|
||||
List<string> subtitles = item.Subtitles.ToList();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Language":
|
||||
string lang = childNode.InnerText;
|
||||
|
||||
if (!string.IsNullOrEmpty(lang))
|
||||
{
|
||||
subtitles.Add(lang);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item.Subtitles = subtitles;
|
||||
}
|
||||
|
||||
protected virtual void FetchFromGenresNode(XmlNode node, T item)
|
||||
{
|
||||
List<string> list = (item.Genres ?? new string[] { }).ToList();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Genre":
|
||||
string text = childNode.InnerText ?? string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
list.Add(text);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
item.Genres = list;
|
||||
}
|
||||
|
||||
protected virtual void FetchDataFromPersonsNode(XmlNode node, T item)
|
||||
{
|
||||
List<Person> list = (item.People ?? new Person[] { }).ToList();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Person":
|
||||
{
|
||||
list.Add(GetPersonFromXmlNode(childNode));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
item.People = list;
|
||||
}
|
||||
|
||||
protected virtual void FetchFromStudiosNode(XmlNode node, T item)
|
||||
{
|
||||
List<string> list = (item.Studios ?? new string[] { }).ToList();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Studio":
|
||||
string text = childNode.InnerText ?? string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
list.Add(text);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item.Studios = list;
|
||||
}
|
||||
|
||||
protected virtual void FetchFromParentalRatingNode(XmlNode node, T item)
|
||||
{
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Value":
|
||||
{
|
||||
int ParentalRating = childNode.SafeGetInt32((int)7);
|
||||
|
||||
switch (ParentalRating)
|
||||
{
|
||||
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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Person GetPersonFromXmlNode(XmlNode node)
|
||||
{
|
||||
Person person = new Person();
|
||||
|
||||
foreach (XmlNode childNode in node.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "Name":
|
||||
person.Name = childNode.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Type":
|
||||
{
|
||||
string type = childNode.InnerText ?? string.Empty;
|
||||
|
||||
if (type == "Director")
|
||||
{
|
||||
person.PersonType = PersonType.Director;
|
||||
}
|
||||
else if (type == "Actor")
|
||||
{
|
||||
person.PersonType = PersonType.Actor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "Role":
|
||||
person.Description = childNode.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return person;
|
||||
}
|
||||
|
||||
protected IEnumerable<string> GetSplitValues(string value, char deliminator)
|
||||
{
|
||||
value = (value ?? string.Empty).Trim(deliminator);
|
||||
|
||||
return string.IsNullOrEmpty(value) ? new string[] { } : value.Split(deliminator);
|
||||
}
|
||||
}
|
||||
}
|
8
MediaBrowser.Controller/Xml/FolderXmlParser.cs
Normal file
8
MediaBrowser.Controller/Xml/FolderXmlParser.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Xml
|
||||
{
|
||||
public class FolderXmlParser : BaseItemXmlParser<Folder>
|
||||
{
|
||||
}
|
||||
}
|
74
MediaBrowser.Controller/Xml/XmlExtensions.cs
Normal file
74
MediaBrowser.Controller/Xml/XmlExtensions.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Controller.Xml
|
||||
{
|
||||
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");
|
||||
|
||||
public static float SafeGetSingle(this XmlNode rvalNode, float minValue, float maxValue)
|
||||
{
|
||||
if (rvalNode.InnerText.Length > 0)
|
||||
{
|
||||
float rval;
|
||||
// float.TryParse is local aware, so it can be probamatic, force us culture
|
||||
if (float.TryParse(rvalNode.InnerText, NumberStyles.AllowDecimalPoint, _usCulture, out rval))
|
||||
{
|
||||
if (rval >= minValue && rval <= maxValue)
|
||||
{
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
5
MediaBrowser.Controller/packages.config
Normal file
5
MediaBrowser.Controller/packages.config
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
|
||||
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
|
||||
</packages>
|
72
MediaBrowser.HtmlBrowser/MediaBrowser.HtmlBrowser.csproj
Normal file
72
MediaBrowser.HtmlBrowser/MediaBrowser.HtmlBrowser.csproj
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.HtmlBrowser</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.HtmlBrowser</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Reactive">
|
||||
<HintPath>..\packages\Rx-Main.1.0.11226\lib\Net4\System.Reactive.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
16
MediaBrowser.HtmlBrowser/Plugin.cs
Normal file
16
MediaBrowser.HtmlBrowser/Plugin.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Linq;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Net;
|
||||
|
||||
namespace MediaBrowser.HtmlBrowser
|
||||
{
|
||||
public class Plugin : BasePlugin<BasePluginConfiguration>
|
||||
{
|
||||
protected override void InitInternal()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.HtmlBrowser/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.HtmlBrowser/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.HtmlBrowser")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.HtmlBrowser")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2b84a02d-40ff-4187-818f-170abc3c31cf")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
4
MediaBrowser.HtmlBrowser/packages.config
Normal file
4
MediaBrowser.HtmlBrowser/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
|
||||
</packages>
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5758B2C7-949A-421D-B268-70A950CF8741}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.InternetProviders</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.InternetProviders</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="PluginConfiguration.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Movies\MediaBrowser.Movies.csproj">
|
||||
<Project>{92b9f802-4415-438f-90e1-44602135ea41}</Project>
|
||||
<Name>MediaBrowser.Movies</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.TV\MediaBrowser.TV.csproj">
|
||||
<Project>{32dfc600-cd2f-4b2d-b39a-3b4c6c32f9b4}</Project>
|
||||
<Name>MediaBrowser.TV</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
11
MediaBrowser.InternetProviders/Plugin.cs
Normal file
11
MediaBrowser.InternetProviders/Plugin.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using MediaBrowser.Common.Plugins;
|
||||
|
||||
namespace MediaBrowser.InternetProviders
|
||||
{
|
||||
public class Plugin : BasePlugin<PluginConfiguration>
|
||||
{
|
||||
protected override void InitInternal()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
8
MediaBrowser.InternetProviders/PluginConfiguration.cs
Normal file
8
MediaBrowser.InternetProviders/PluginConfiguration.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using MediaBrowser.Common.Plugins;
|
||||
|
||||
namespace MediaBrowser.InternetProviders
|
||||
{
|
||||
public class PluginConfiguration : BasePluginConfiguration
|
||||
{
|
||||
}
|
||||
}
|
36
MediaBrowser.InternetProviders/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.InternetProviders/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.InternetProviders")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.InternetProviders")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("520717d0-3257-41b2-8da2-6aa8b8248250")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
17
MediaBrowser.Model/Configuration/Configuration.cs
Normal file
17
MediaBrowser.Model/Configuration/Configuration.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using MediaBrowser.Common.Logging;
|
||||
|
||||
namespace MediaBrowser.Model.Configuration
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
public string ImagesByNamePath { get; set; }
|
||||
public int HttpServerPortNumber { get; set; }
|
||||
public LogSeverity LogSeverity { get; set; }
|
||||
|
||||
public Configuration()
|
||||
{
|
||||
HttpServerPortNumber = 8096;
|
||||
LogSeverity = Common.Logging.LogSeverity.Info;
|
||||
}
|
||||
}
|
||||
}
|
12
MediaBrowser.Model/Entities/Audio.cs
Normal file
12
MediaBrowser.Model/Entities/Audio.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public class Audio : BaseItem
|
||||
{
|
||||
}
|
||||
}
|
64
MediaBrowser.Model/Entities/BaseItem.cs
Normal file
64
MediaBrowser.Model/Entities/BaseItem.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public abstract class BaseItem
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string SortName { get; set; }
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTime DateCreated { get; set; }
|
||||
public DateTime DateModified { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Folder Parent { get; set; }
|
||||
|
||||
public string PrimaryImagePath { get; set; }
|
||||
public string LogoImagePath { get; set; }
|
||||
public string ArtImagePath { get; set; }
|
||||
public string ThumbnailImagePath { get; set; }
|
||||
public string BannerImagePath { get; set; }
|
||||
|
||||
public IEnumerable<string> BackdropImagePaths { get; set; }
|
||||
|
||||
public string OfficialRating { get; set; }
|
||||
|
||||
public string CustomRating { get; set; }
|
||||
public string CustomPin { get; set; }
|
||||
|
||||
public string Overview { get; set; }
|
||||
public string Tagline { get; set; }
|
||||
|
||||
public IEnumerable<Person> People { get; set; }
|
||||
|
||||
public IEnumerable<string> Studios { get; set; }
|
||||
|
||||
public IEnumerable<string> Genres { get; set; }
|
||||
|
||||
public string DisplayMediaType { get; set; }
|
||||
|
||||
public float? UserRating { get; set; }
|
||||
public TimeSpan? RunTime { get; set; }
|
||||
|
||||
public string AspectRatio { get; set; }
|
||||
public int? ProductionYear { get; set; }
|
||||
|
||||
public IEnumerable<Video> LocalTrailers { get; set; }
|
||||
|
||||
public string TrailerUrl { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
96
MediaBrowser.Model/Entities/Folder.cs
Normal file
96
MediaBrowser.Model/Entities/Folder.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public class Folder : BaseItem
|
||||
{
|
||||
public bool IsRoot { get; set; }
|
||||
|
||||
public bool IsVirtualFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Parent != null && Parent.IsRoot;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public BaseItem[] Children { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IEnumerable<Folder> FolderChildren { get { return Children.OfType<Folder>(); } }
|
||||
|
||||
public Folder GetFolderByName(string name)
|
||||
{
|
||||
return FolderChildren.FirstOrDefault(f => System.IO.Path.GetFileName(f.Path).Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds an item by ID, recursively
|
||||
/// </summary>
|
||||
public BaseItem FindById(Guid id)
|
||||
{
|
||||
if (Id == id)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
foreach (BaseItem item in Children)
|
||||
{
|
||||
if (item.Id == id)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Folder folder in FolderChildren)
|
||||
{
|
||||
BaseItem item = folder.FindById(id);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds an item by path, recursively
|
||||
/// </summary>
|
||||
public BaseItem FindByPath(string path)
|
||||
{
|
||||
if (Path.Equals(path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
foreach (BaseItem item in Children)
|
||||
{
|
||||
if (item.Path.Equals(path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Folder folder in FolderChildren)
|
||||
{
|
||||
BaseItem item = folder.FindByPath(path);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
22
MediaBrowser.Model/Entities/Person.cs
Normal file
22
MediaBrowser.Model/Entities/Person.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public PersonType PersonType { get; set; }
|
||||
}
|
||||
|
||||
public enum PersonType
|
||||
{
|
||||
Actor = 1,
|
||||
Director = 2,
|
||||
Writer = 3
|
||||
}
|
||||
}
|
12
MediaBrowser.Model/Entities/PlaybackStatus.cs
Normal file
12
MediaBrowser.Model/Entities/PlaybackStatus.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public class PlaybackStatus
|
||||
{
|
||||
}
|
||||
}
|
42
MediaBrowser.Model/Entities/Video.cs
Normal file
42
MediaBrowser.Model/Entities/Video.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public class Video : BaseItem
|
||||
{
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
private IEnumerable<string> _Subtitles = new string[] { };
|
||||
public IEnumerable<string> Subtitles { get { return _Subtitles; } set { _Subtitles = value; } }
|
||||
|
||||
private IEnumerable<AudioStream> _AudioStreams = new AudioStream[] { };
|
||||
public IEnumerable<AudioStream> AudioStreams { get { return _AudioStreams; } set { _AudioStreams = value; } }
|
||||
|
||||
public int Height { get; set; }
|
||||
public int Width { get; set; }
|
||||
public string ScanType { get; set; }
|
||||
public string FrameRate { get; set; }
|
||||
public int VideoBitRate { get; set; }
|
||||
public string VideoCodec { get; set; }
|
||||
}
|
||||
|
||||
public class AudioStream
|
||||
{
|
||||
public string AudioFormat { get; set; }
|
||||
public string AudioProfile { get; set; }
|
||||
public string Language { get; set; }
|
||||
public int BitRate { get; set; }
|
||||
public int Channels { get; set; }
|
||||
}
|
||||
|
||||
public enum VideoType
|
||||
{
|
||||
VideoFile = 1,
|
||||
DVD = 2,
|
||||
BluRay = 3
|
||||
}
|
||||
}
|
73
MediaBrowser.Model/MediaBrowser.Model.csproj
Normal file
73
MediaBrowser.Model/MediaBrowser.Model.csproj
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Model</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Model</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration\Configuration.cs" />
|
||||
<Compile Include="Entities\Person.cs" />
|
||||
<Compile Include="Entities\Audio.cs" />
|
||||
<Compile Include="Entities\BaseItem.cs" />
|
||||
<Compile Include="Entities\Folder.cs" />
|
||||
<Compile Include="Entities\PlaybackStatus.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Users\User.cs" />
|
||||
<Compile Include="Users\UserItemData.cs" />
|
||||
<Compile Include="Entities\Video.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
36
MediaBrowser.Model/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Model/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Model")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Model")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("4478b410-9582-4c22-b890-2a309708b9f1")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
19
MediaBrowser.Model/Users/User.cs
Normal file
19
MediaBrowser.Model/Users/User.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Model.Users
|
||||
{
|
||||
public class User : BaseItem
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public string MaxParentalRating { get; set; }
|
||||
public bool HideBlockedContent { get; set; }
|
||||
|
||||
private Dictionary<Guid, UserItemData> _ItemData = new Dictionary<Guid, UserItemData>();
|
||||
public Dictionary<Guid, UserItemData> ItemData { get { return _ItemData; } set { _ItemData = value; } }
|
||||
}
|
||||
}
|
23
MediaBrowser.Model/Users/UserItemData.cs
Normal file
23
MediaBrowser.Model/Users/UserItemData.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Model.Users
|
||||
{
|
||||
public class UserItemData
|
||||
{
|
||||
public UserItemRating Rating { get; set; }
|
||||
|
||||
public PlaybackStatus PlaybackStatus { get; set; }
|
||||
}
|
||||
|
||||
public enum UserItemRating
|
||||
{
|
||||
Likes,
|
||||
Dislikes,
|
||||
Favorite
|
||||
}
|
||||
}
|
4
MediaBrowser.Model/packages.config
Normal file
4
MediaBrowser.Model/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
|
||||
</packages>
|
10
MediaBrowser.Movies/Entities/BoxSet.cs
Normal file
10
MediaBrowser.Movies/Entities/BoxSet.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Movies.Entities
|
||||
{
|
||||
public class BoxSet : Folder
|
||||
{
|
||||
}
|
||||
}
|
14
MediaBrowser.Movies/Entities/Movie.cs
Normal file
14
MediaBrowser.Movies/Entities/Movie.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Movies.Entities
|
||||
{
|
||||
public class Movie : Video
|
||||
{
|
||||
public string TmdbId { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
|
||||
public IEnumerable<Video> SpecialFeatures { get; set; }
|
||||
}
|
||||
}
|
75
MediaBrowser.Movies/MediaBrowser.Movies.csproj
Normal file
75
MediaBrowser.Movies/MediaBrowser.Movies.csproj
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{92B9F802-4415-438F-90E1-44602135EA41}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Movies</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Movies</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Entities\BoxSet.cs" />
|
||||
<Compile Include="Resolvers\BoxSetResolver.cs" />
|
||||
<Compile Include="Entities\Movie.cs" />
|
||||
<Compile Include="Resolvers\MovieResolver.cs" />
|
||||
<Compile Include="Metadata\MovieXmlParser.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
35
MediaBrowser.Movies/Metadata/MovieXmlParser.cs
Normal file
35
MediaBrowser.Movies/Metadata/MovieXmlParser.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System.Linq;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Xml;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Movies.Entities;
|
||||
|
||||
namespace MediaBrowser.Movies.Metadata
|
||||
{
|
||||
public class MovieXmlParser : BaseItemXmlParser<Movie>
|
||||
{
|
||||
protected override void FetchDataFromXmlNode(XmlNode node, Movie item)
|
||||
{
|
||||
switch (node.Name)
|
||||
{
|
||||
case "TMDbId":
|
||||
item.TmdbId = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "IMDB":
|
||||
case "IMDbId":
|
||||
string IMDbId = node.InnerText ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(IMDbId))
|
||||
{
|
||||
item.ImdbId = IMDbId;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
base.FetchDataFromXmlNode(node, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
MediaBrowser.Movies/Plugin.cs
Normal file
24
MediaBrowser.Movies/Plugin.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Movies.Entities;
|
||||
using MediaBrowser.Movies.Resolvers;
|
||||
|
||||
namespace MediaBrowser.Movies
|
||||
{
|
||||
public class Plugin : BasePlugin<BasePluginConfiguration>
|
||||
{
|
||||
protected override void InitInternal()
|
||||
{
|
||||
Kernel.Instance.AddBaseItemType<BoxSet, BoxSetResolver>();
|
||||
Kernel.Instance.AddBaseItemType<Movie, MovieResolver>();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
Kernel.Instance.RemoveBaseItemType<Movie, MovieResolver>();
|
||||
Kernel.Instance.RemoveBaseItemType<BoxSet, BoxSetResolver>();
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Movies/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Movies/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Movies")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Movies")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("e7616f1d-840f-4ada-bc58-e885035fbc1b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
24
MediaBrowser.Movies/Resolvers/BoxSetResolver.cs
Normal file
24
MediaBrowser.Movies/Resolvers/BoxSetResolver.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Movies.Entities;
|
||||
|
||||
namespace MediaBrowser.Movies.Resolvers
|
||||
{
|
||||
public class BoxSetResolver : BaseFolderResolver<BoxSet>
|
||||
{
|
||||
protected override BoxSet Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.IsFolder)
|
||||
{
|
||||
if (Path.GetFileName(args.Path).IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return new BoxSet();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
83
MediaBrowser.Movies/Resolvers/MovieResolver.cs
Normal file
83
MediaBrowser.Movies/Resolvers/MovieResolver.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Movies.Entities;
|
||||
using MediaBrowser.Movies.Metadata;
|
||||
|
||||
namespace MediaBrowser.Movies.Resolvers
|
||||
{
|
||||
public class MovieResolver : BaseVideoResolver<Movie>
|
||||
{
|
||||
protected override Movie Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.IsFolder)
|
||||
{
|
||||
var metadataFile = args.GetFileByName("movie.xml");
|
||||
|
||||
if (metadataFile.HasValue || Path.GetFileName(args.Path).IndexOf("[tmdbid=", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return GetMovie(args);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Movie GetMovie(ItemResolveEventArgs args)
|
||||
{
|
||||
foreach (var child in args.FileSystemChildren)
|
||||
{
|
||||
ItemResolveEventArgs childArgs = new ItemResolveEventArgs()
|
||||
{
|
||||
Path = child.Key,
|
||||
FileAttributes = child.Value,
|
||||
FileSystemChildren = new KeyValuePair<string, FileAttributes>[] { }
|
||||
};
|
||||
|
||||
var item = base.Resolve(childArgs);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
return new Movie()
|
||||
{
|
||||
Path = item.Path,
|
||||
VideoType = item.VideoType
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new Movie();
|
||||
}
|
||||
|
||||
private void PopulateBonusFeatures(Movie item, ItemResolveEventArgs args)
|
||||
{
|
||||
var trailerPath = args.GetFolderByName("specials");
|
||||
|
||||
if (trailerPath.HasValue)
|
||||
{
|
||||
string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
item.SpecialFeatures = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(f)).OfType<Video>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetItemValues(Movie item, ItemResolveEventArgs args)
|
||||
{
|
||||
base.SetItemValues(item, args);
|
||||
|
||||
var metadataFile = args.GetFileByName("movie.xml");
|
||||
|
||||
if (metadataFile.HasValue)
|
||||
{
|
||||
new MovieXmlParser().Fetch(item, metadataFile.Value.Key);
|
||||
}
|
||||
|
||||
PopulateBonusFeatures(item, args);
|
||||
}
|
||||
}
|
||||
}
|
17
MediaBrowser.Program/App.config
Normal file
17
MediaBrowser.Program/App.config
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="DataPath" value="..\..\..\ProgramData" />
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
69
MediaBrowser.Program/MediaBrowser.Program.csproj
Normal file
69
MediaBrowser.Program/MediaBrowser.Program.csproj
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.Program</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.Program</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
48
MediaBrowser.Program/Program.cs
Normal file
48
MediaBrowser.Program/Program.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace MediaBrowser.Program
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
LoadKernel();
|
||||
}
|
||||
|
||||
private static void LoadKernel()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
Console.WriteLine("Loading");
|
||||
|
||||
string installDir = ConfigurationManager.AppSettings["DataPath"];
|
||||
|
||||
if (!Path.IsPathRooted(installDir))
|
||||
{
|
||||
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
path = Path.GetDirectoryName(path);
|
||||
|
||||
installDir = Path.Combine(path, installDir);
|
||||
|
||||
installDir = Path.GetFullPath(installDir);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(installDir))
|
||||
{
|
||||
Directory.CreateDirectory(installDir);
|
||||
}
|
||||
|
||||
Kernel kernel = new Kernel(installDir);
|
||||
|
||||
kernel.Init();
|
||||
|
||||
var time = DateTime.Now - now;
|
||||
Console.WriteLine("Done in " + time.TotalSeconds + " seconds");
|
||||
Console.WriteLine("Press Enter to quit.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.Program/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.Program/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.Program")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.Program")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("4be8a93f-7491-48e4-9400-f3a95a7bbdb2")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
13
MediaBrowser.TV/Entities/Episode.cs
Normal file
13
MediaBrowser.TV/Entities/Episode.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.TV.Entities
|
||||
{
|
||||
public class Episode : Video
|
||||
{
|
||||
public string SeasonNumber { get; set; }
|
||||
public string EpisodeNumber { get; set; }
|
||||
public string FirstAired { get; set; }
|
||||
}
|
||||
}
|
16
MediaBrowser.TV/Entities/Season.cs
Normal file
16
MediaBrowser.TV/Entities/Season.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MediaBrowser.TV.Entities
|
||||
{
|
||||
public class Season : Folder
|
||||
{
|
||||
/// <summary>
|
||||
/// Store these to reduce disk access in Episode Resolver
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public IEnumerable<string> MetadataFiles { get; set; }
|
||||
}
|
||||
}
|
12
MediaBrowser.TV/Entities/Series.cs
Normal file
12
MediaBrowser.TV/Entities/Series.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.TV.Entities
|
||||
{
|
||||
public class Series : Folder
|
||||
{
|
||||
public string TVDBSeriesId { get; set; }
|
||||
public string Status { get; set; }
|
||||
}
|
||||
}
|
86
MediaBrowser.TV/MediaBrowser.TV.csproj
Normal file
86
MediaBrowser.TV/MediaBrowser.TV.csproj
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.TV</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.TV</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.4.5.7\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Entities\Episode.cs" />
|
||||
<Compile Include="Resolvers\EpisodeResolver.cs" />
|
||||
<Compile Include="Metadata\EpisodeXmlParser.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Entities\Season.cs" />
|
||||
<Compile Include="Resolvers\SeasonResolver.cs" />
|
||||
<Compile Include="Entities\Series.cs" />
|
||||
<Compile Include="Resolvers\SeriesResolver.cs" />
|
||||
<Compile Include="Metadata\SeriesXmlParser.cs" />
|
||||
<Compile Include="TVUtils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
62
MediaBrowser.TV/Metadata/EpisodeXmlParser.cs
Normal file
62
MediaBrowser.TV/Metadata/EpisodeXmlParser.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Xml;
|
||||
using MediaBrowser.TV.Entities;
|
||||
|
||||
namespace MediaBrowser.TV.Metadata
|
||||
{
|
||||
public class EpisodeXmlParser : BaseItemXmlParser<Episode>
|
||||
{
|
||||
protected override void FetchDataFromXmlNode(XmlNode node, Episode item)
|
||||
{
|
||||
switch (node.Name)
|
||||
{
|
||||
case "filename":
|
||||
{
|
||||
string filename = node.InnerText;
|
||||
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
string metadataFolder = Path.GetDirectoryName(item.Path);
|
||||
item.PrimaryImagePath = Path.Combine(metadataFolder, filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "EpisodeNumber":
|
||||
item.EpisodeNumber = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "SeasonNumber":
|
||||
item.SeasonNumber = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "EpisodeName":
|
||||
item.Name = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "FirstAired":
|
||||
{
|
||||
item.FirstAired = node.InnerText ?? string.Empty;
|
||||
|
||||
if (!string.IsNullOrEmpty(item.FirstAired))
|
||||
{
|
||||
DateTime airDate;
|
||||
int y = DateTime.TryParse(item.FirstAired, out airDate) ? airDate.Year : -1;
|
||||
if (y > 1850)
|
||||
{
|
||||
item.ProductionYear = y;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
base.FetchDataFromXmlNode(node, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
MediaBrowser.TV/Metadata/SeriesXmlParser.cs
Normal file
47
MediaBrowser.TV/Metadata/SeriesXmlParser.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Controller.Xml;
|
||||
using MediaBrowser.TV.Entities;
|
||||
|
||||
namespace MediaBrowser.TV.Metadata
|
||||
{
|
||||
public class SeriesXmlParser : BaseItemXmlParser<Series>
|
||||
{
|
||||
protected override void FetchDataFromXmlNode(XmlNode node, Series item)
|
||||
{
|
||||
switch (node.Name)
|
||||
{
|
||||
case "id":
|
||||
item.TVDBSeriesId = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "SeriesName":
|
||||
item.Name = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Status":
|
||||
item.Status = node.InnerText ?? string.Empty;
|
||||
break;
|
||||
|
||||
case "Runtime":
|
||||
{
|
||||
string text = node.InnerText ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
|
||||
int runtime;
|
||||
if (int.TryParse(text.Split(' ')[0], out runtime))
|
||||
{
|
||||
item.RunTime = TimeSpan.FromMinutes(runtime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
base.FetchDataFromXmlNode(node, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
MediaBrowser.TV/Plugin.cs
Normal file
44
MediaBrowser.TV/Plugin.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.TV.Entities;
|
||||
using MediaBrowser.TV.Resolvers;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.TV
|
||||
{
|
||||
public class Plugin : BasePlugin<BasePluginConfiguration>
|
||||
{
|
||||
protected override void InitInternal()
|
||||
{
|
||||
Kernel.Instance.AddBaseItemType<Series, SeriesResolver>();
|
||||
Kernel.Instance.AddBaseItemType<Season, SeasonResolver>();
|
||||
Kernel.Instance.AddBaseItemType<Episode, EpisodeResolver>();
|
||||
|
||||
Kernel.Instance.ItemController.PreBeginResolvePath += ItemController_PreBeginResolvePath;
|
||||
}
|
||||
|
||||
void ItemController_PreBeginResolvePath(object sender, PreBeginResolveEventArgs e)
|
||||
{
|
||||
if (e.IsFolder && System.IO.Path.GetFileName(e.Path).Equals("metadata", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (e.Parent is Season || e.Parent is Series)
|
||||
{
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
Kernel.Instance.RemoveBaseItemType<Series, SeriesResolver>();
|
||||
Kernel.Instance.RemoveBaseItemType<Season, SeasonResolver>();
|
||||
Kernel.Instance.RemoveBaseItemType<Episode, EpisodeResolver>();
|
||||
|
||||
Kernel.Instance.ItemController.PreBeginResolvePath -= ItemController_PreBeginResolvePath;
|
||||
}
|
||||
}
|
||||
}
|
36
MediaBrowser.TV/Properties/AssemblyInfo.cs
Normal file
36
MediaBrowser.TV/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.TV")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.TV")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1646eb9e-3f4f-46ea-b1e9-09bc85c1143a")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
83
MediaBrowser.TV/Resolvers/EpisodeResolver.cs
Normal file
83
MediaBrowser.TV/Resolvers/EpisodeResolver.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.TV.Entities;
|
||||
using MediaBrowser.TV.Metadata;
|
||||
|
||||
namespace MediaBrowser.TV.Resolvers
|
||||
{
|
||||
class EpisodeResolver : BaseVideoResolver<Episode>
|
||||
{
|
||||
protected override Episode Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.Parent is Season || args.Parent is Series)
|
||||
{
|
||||
return base.Resolve(args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void SetItemValues(Episode item, ItemResolveEventArgs args)
|
||||
{
|
||||
base.SetItemValues(item, args);
|
||||
|
||||
string metadataFolder = Path.Combine(args.Parent.Path, "metadata");
|
||||
|
||||
string episodeFileName = Path.GetFileName(item.Path);
|
||||
|
||||
string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".xml"));
|
||||
|
||||
Season season = args.Parent as Season;
|
||||
|
||||
FetchMetadata(item, season, metadataFile);
|
||||
|
||||
if (string.IsNullOrEmpty(item.PrimaryImagePath))
|
||||
{
|
||||
SetPrimaryImagePath(item, season, metadataFolder, episodeFileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void FetchMetadata(Episode item, Season season, string metadataFile)
|
||||
{
|
||||
if (season == null)
|
||||
{
|
||||
// Episode directly in Series folder
|
||||
// Need to validate it the slow way
|
||||
if (!File.Exists(metadataFile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!season.MetadataFiles.Any(s => s.Equals(metadataFile, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
new EpisodeXmlParser().Fetch(item, metadataFile);
|
||||
}
|
||||
|
||||
private void SetPrimaryImagePath(Episode item, Season season, string metadataFolder, string episodeFileName)
|
||||
{
|
||||
string[] imageFiles = new string[] {
|
||||
Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".jpg")),
|
||||
Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".png"))
|
||||
};
|
||||
|
||||
if (season == null)
|
||||
{
|
||||
// Gotta do this the slow way
|
||||
item.PrimaryImagePath = imageFiles.FirstOrDefault(f => File.Exists(f));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.PrimaryImagePath = imageFiles.FirstOrDefault(f => season.MetadataFiles.Any(s => s.Equals(f, StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
MediaBrowser.TV/Resolvers/SeasonResolver.cs
Normal file
33
MediaBrowser.TV/Resolvers/SeasonResolver.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.TV.Entities;
|
||||
|
||||
namespace MediaBrowser.TV.Resolvers
|
||||
{
|
||||
class SeasonResolver : BaseFolderResolver<Season>
|
||||
{
|
||||
protected override Season Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.IsFolder && args.Parent is Series)
|
||||
{
|
||||
Season season = new Season();
|
||||
|
||||
if (args.ContainsFolder("metadata"))
|
||||
{
|
||||
season.MetadataFiles = Directory.GetFiles(Path.Combine(args.Path, "metadata"), "*", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
season.MetadataFiles = new string[] { };
|
||||
}
|
||||
|
||||
return season;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
40
MediaBrowser.TV/Resolvers/SeriesResolver.cs
Normal file
40
MediaBrowser.TV/Resolvers/SeriesResolver.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Events;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.TV.Entities;
|
||||
using MediaBrowser.TV.Metadata;
|
||||
|
||||
namespace MediaBrowser.TV.Resolvers
|
||||
{
|
||||
class SeriesResolver : BaseFolderResolver<Series>
|
||||
{
|
||||
protected override Series Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
if (args.IsFolder)
|
||||
{
|
||||
var metadataFile = args.GetFileByName("series.xml");
|
||||
|
||||
if (metadataFile.HasValue || Path.GetFileName(args.Path).IndexOf("[tvdbid=", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return new Series();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void SetItemValues(Series item, ItemResolveEventArgs args)
|
||||
{
|
||||
base.SetItemValues(item, args);
|
||||
|
||||
var metadataFile = args.GetFileByName("series.xml");
|
||||
|
||||
if (metadataFile.HasValue)
|
||||
{
|
||||
new SeriesXmlParser().Fetch(item, metadataFile.Value.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
MediaBrowser.TV/TVUtils.cs
Normal file
104
MediaBrowser.TV/TVUtils.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.TV
|
||||
{
|
||||
public static class TVUtils
|
||||
{
|
||||
private static readonly Regex[] seasonPathExpressions = new Regex[] {
|
||||
new Regex(@".+\\[s|S]eason\s?(?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[s|S]æson\s?(?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[t|T]emporada\s?(?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[s|S]aison\s?(?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[s|S]taffel\s?(?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[s|S](?<seasonnumber>\d{1,2})$"),
|
||||
new Regex(@".+\\[s|S]eason\s?(?<seasonnumber>\d{1,2})[^\\]*$")
|
||||
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Used to detect paths that represent episodes, need to make sure they don't also
|
||||
/// match movie titles like "2001 A Space..."
|
||||
/// Currently we limit the numbers here to 2 digits to try and avoid this
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The order here is important, if the order is changed some of the later
|
||||
/// ones might incorrectly match things that higher ones would have caught.
|
||||
/// The most restrictive expressions should appear first
|
||||
/// </remarks>
|
||||
private static readonly Regex[] episodeExpressions = new Regex[] {
|
||||
new Regex(@".*\\[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi
|
||||
new Regex(@".*\\[s|S](?<seasonnumber>\d{1,2})x?[e|E](?<epnumber>\d{1,3})[^\\]*$"), // S01E02 blah.avi, S01xE01 blah.avi
|
||||
new Regex(@".*\\(?<seriesname>[^\\]*)[s|S]?(?<seasonnumber>\d{1,2})[x|X](?<epnumber>\d{1,3})[^\\]*$"), // 01x02 blah.avi S01x01 balh.avi
|
||||
new Regex(@".*\\(?<seriesname>[^\\]*)[s|S](?<seasonnumber>\d{1,2})[x|X|\.]?[e|E](?<epnumber>\d{1,3})[^\\]*$") // S01E02 blah.avi, S01xE01 blah.avi
|
||||
};
|
||||
/// <summary>
|
||||
/// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season
|
||||
/// </summary>
|
||||
private static readonly Regex[] episodeExpressionsInASeasonFolder = new Regex[] {
|
||||
new Regex(@".*\\(?<epnumber>\d{1,2})\s?-\s?[^\\]*$"), // 01 - blah.avi, 01-blah.avi
|
||||
new Regex(@".*\\(?<epnumber>\d{1,2})[^\d\\]*[^\\]*$"), // 01.avi, 01.blah.avi "01 - 22 blah.avi"
|
||||
new Regex(@".*\\(?<seasonnumber>\d)(?<epnumber>\d{1,2})[^\d\\]+[^\\]*$"), // 01.avi, 01.blah.avi
|
||||
new Regex(@".*\\\D*\d+(?<epnumber>\d{2})") // hell0 - 101 - hello.avi
|
||||
|
||||
};
|
||||
|
||||
public static bool IsSeasonFolder(string path)
|
||||
{
|
||||
path = path.ToLower();
|
||||
|
||||
return seasonPathExpressions.Any(r => r.IsMatch(path));
|
||||
}
|
||||
|
||||
public static bool IsSeriesFolder(string path, IEnumerable<string> files, IEnumerable<string> folders)
|
||||
{
|
||||
if (folders.Any(f => IsSeasonFolder(f)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return files.Any(f => !string.IsNullOrEmpty(EpisodeNumberFromFile(f, false)));
|
||||
}
|
||||
|
||||
public static bool IsEpisode(string fullPath)
|
||||
{
|
||||
bool isInSeason = IsSeasonFolder(Path.GetDirectoryName(fullPath));
|
||||
|
||||
if (isInSeason)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (EpisodeNumberFromFile(fullPath, isInSeason) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string EpisodeNumberFromFile(string fullPath, bool isInSeason)
|
||||
{
|
||||
string fl = fullPath.ToLower();
|
||||
foreach (Regex r in episodeExpressions)
|
||||
{
|
||||
Match m = r.Match(fl);
|
||||
if (m.Success)
|
||||
return m.Groups["epnumber"].Value;
|
||||
}
|
||||
if (isInSeason)
|
||||
{
|
||||
foreach (Regex r in episodeExpressionsInASeasonFolder)
|
||||
{
|
||||
Match m = r.Match(fl);
|
||||
if (m.Success)
|
||||
return m.Groups["epnumber"].Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
4
MediaBrowser.TV/packages.config
Normal file
4
MediaBrowser.TV/packages.config
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
|
||||
</packages>
|
77
MediaBrowser.sln
Normal file
77
MediaBrowser.sln
Normal file
|
@ -0,0 +1,77 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Movies", "MediaBrowser.Movies\MediaBrowser.Movies.csproj", "{92B9F802-4415-438F-90E1-44602135EA41}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.TV", "MediaBrowser.TV\MediaBrowser.TV.csproj", "{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Configuration", "MediaBrowser.Configuration\MediaBrowser.Configuration.csproj", "{933CC468-E22B-48D8-8BCA-2E026F411CA2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Program", "MediaBrowser.Program\MediaBrowser.Program.csproj", "{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.InternetProviders", "MediaBrowser.InternetProviders\MediaBrowser.InternetProviders.csproj", "{5758B2C7-949A-421D-B268-70A950CF8741}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.HtmlBrowser", "MediaBrowser.HtmlBrowser\MediaBrowser.HtmlBrowser.csproj", "{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32DFC600-CD2F-4B2D-B39A-3B4C6C32F9B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5758B2C7-949A-421D-B268-70A950CF8741}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5758B2C7-949A-421D-B268-70A950CF8741}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5758B2C7-949A-421D-B268-70A950CF8741}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5758B2C7-949A-421D-B268-70A950CF8741}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{92B9F802-4415-438F-90E1-44602135EA41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{92B9F802-4415-438F-90E1-44602135EA41}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92B9F802-4415-438F-90E1-44602135EA41}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92B9F802-4415-438F-90E1-44602135EA41}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{933CC468-E22B-48D8-8BCA-2E026F411CA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{933CC468-E22B-48D8-8BCA-2E026F411CA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{933CC468-E22B-48D8-8BCA-2E026F411CA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{933CC468-E22B-48D8-8BCA-2E026F411CA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
Reference in New Issue
Block a user