Initial check-in

This commit is contained in:
LukePulverenti Luke Pulverenti luke pulverenti 2012-07-12 02:55:27 -04:00
commit b50f78e5da
93 changed files with 5325 additions and 0 deletions

37
.hgignore Normal file
View 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

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

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

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

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

View 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")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
</packages>

View File

@ -0,0 +1,9 @@
using System;
namespace MediaBrowser.Common.Events
{
public class GenericItemEventArgs<TItemType> : EventArgs
{
public TItemType Item { get; set; }
}
}

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

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

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

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

View 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
}
}

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

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

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

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

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

View 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")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
</packages>

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

View File

@ -0,0 +1,11 @@
using MediaBrowser.Common.Plugins;
namespace MediaBrowser.Configuration
{
public class Plugin : BasePlugin<BasePluginConfiguration>
{
protected override void InitInternal()
{
}
}
}

View 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")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
</packages>

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

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

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

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

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

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

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

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

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

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

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

View 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))
{
}
}*/
}

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

View 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")]

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

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

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

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

View 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"));
}
}
}

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

View File

@ -0,0 +1,8 @@
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Xml
{
public class FolderXmlParser : BaseItemXmlParser<Folder>
{
}
}

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

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

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

View 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()
{
}
}
}

View 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")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Main" version="1.0.11226" targetFramework="net45" />
</packages>

View 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>{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>

View File

@ -0,0 +1,11 @@
using MediaBrowser.Common.Plugins;
namespace MediaBrowser.InternetProviders
{
public class Plugin : BasePlugin<PluginConfiguration>
{
protected override void InitInternal()
{
}
}
}

View File

@ -0,0 +1,8 @@
using MediaBrowser.Common.Plugins;
namespace MediaBrowser.InternetProviders
{
public class PluginConfiguration : BasePluginConfiguration
{
}
}

View 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")]

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

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

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

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

View 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
}
}

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

View 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
}
}

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

View 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")]

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

View 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
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="4.5.7" targetFramework="net45" />
</packages>

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Movies.Entities
{
public class BoxSet : Folder
{
}
}

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

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

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

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

View 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")]

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

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

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

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

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

View 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")]

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

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

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

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

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

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

View 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")]

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

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

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

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