aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Common.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Common.Implementations')
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationPaths.cs304
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj87
-rw-r--r--MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs31
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs322
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs119
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs107
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs71
-rw-r--r--MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs122
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs240
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs158
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs140
-rw-r--r--MediaBrowser.Common.Implementations/packages.config5
12 files changed, 1706 insertions, 0 deletions
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
new file mode 100644
index 000000000..93478b22c
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
@@ -0,0 +1,304 @@
+using System;
+using System.Configuration;
+using System.IO;
+using System.Reflection;
+
+namespace MediaBrowser.Common.Implementations
+{
+ /// <summary>
+ /// Provides a base class to hold common application paths used by both the Ui and Server.
+ /// This can be subclassed to add application-specific paths.
+ /// </summary>
+ public abstract class BaseApplicationPaths
+ {
+ /// <summary>
+ /// The _program data path
+ /// </summary>
+ private string _programDataPath;
+ /// <summary>
+ /// Gets the path to the program data folder
+ /// </summary>
+ /// <value>The program data path.</value>
+ public string ProgramDataPath
+ {
+ get
+ {
+ return _programDataPath ?? (_programDataPath = GetProgramDataPath());
+ }
+ }
+
+ /// <summary>
+ /// The _data directory
+ /// </summary>
+ private string _dataDirectory;
+ /// <summary>
+ /// Gets the folder path to the data directory
+ /// </summary>
+ /// <value>The data directory.</value>
+ public string DataPath
+ {
+ get
+ {
+ if (_dataDirectory == null)
+ {
+ _dataDirectory = Path.Combine(ProgramDataPath, "data");
+
+ if (!Directory.Exists(_dataDirectory))
+ {
+ Directory.CreateDirectory(_dataDirectory);
+ }
+ }
+
+ return _dataDirectory;
+ }
+ }
+
+ /// <summary>
+ /// The _image cache path
+ /// </summary>
+ private string _imageCachePath;
+ /// <summary>
+ /// Gets the image cache path.
+ /// </summary>
+ /// <value>The image cache path.</value>
+ public string ImageCachePath
+ {
+ get
+ {
+ if (_imageCachePath == null)
+ {
+ _imageCachePath = Path.Combine(CachePath, "images");
+
+ if (!Directory.Exists(_imageCachePath))
+ {
+ Directory.CreateDirectory(_imageCachePath);
+ }
+ }
+
+ return _imageCachePath;
+ }
+ }
+
+ /// <summary>
+ /// The _plugins path
+ /// </summary>
+ private string _pluginsPath;
+ /// <summary>
+ /// Gets the path to the plugin directory
+ /// </summary>
+ /// <value>The plugins path.</value>
+ public string PluginsPath
+ {
+ get
+ {
+ if (_pluginsPath == null)
+ {
+ _pluginsPath = Path.Combine(ProgramDataPath, "plugins");
+ if (!Directory.Exists(_pluginsPath))
+ {
+ Directory.CreateDirectory(_pluginsPath);
+ }
+ }
+
+ return _pluginsPath;
+ }
+ }
+
+ /// <summary>
+ /// The _plugin configurations path
+ /// </summary>
+ private string _pluginConfigurationsPath;
+ /// <summary>
+ /// Gets the path to the plugin configurations directory
+ /// </summary>
+ /// <value>The plugin configurations path.</value>
+ public string PluginConfigurationsPath
+ {
+ get
+ {
+ if (_pluginConfigurationsPath == null)
+ {
+ _pluginConfigurationsPath = Path.Combine(PluginsPath, "configurations");
+ if (!Directory.Exists(_pluginConfigurationsPath))
+ {
+ Directory.CreateDirectory(_pluginConfigurationsPath);
+ }
+ }
+
+ return _pluginConfigurationsPath;
+ }
+ }
+
+ private string _tempUpdatePath;
+ /// <summary>
+ /// Gets the path to where temporary update files will be stored
+ /// </summary>
+ /// <value>The plugin configurations path.</value>
+ public string TempUpdatePath
+ {
+ get
+ {
+ if (_tempUpdatePath == null)
+ {
+ _tempUpdatePath = Path.Combine(ProgramDataPath, "Updates");
+ if (!Directory.Exists(_tempUpdatePath))
+ {
+ Directory.CreateDirectory(_tempUpdatePath);
+ }
+ }
+
+ return _tempUpdatePath;
+ }
+ }
+
+ /// <summary>
+ /// The _log directory path
+ /// </summary>
+ private string _logDirectoryPath;
+ /// <summary>
+ /// Gets the path to the log directory
+ /// </summary>
+ /// <value>The log directory path.</value>
+ public string LogDirectoryPath
+ {
+ get
+ {
+ if (_logDirectoryPath == null)
+ {
+ _logDirectoryPath = Path.Combine(ProgramDataPath, "logs");
+ if (!Directory.Exists(_logDirectoryPath))
+ {
+ Directory.CreateDirectory(_logDirectoryPath);
+ }
+ }
+ return _logDirectoryPath;
+ }
+ }
+
+ /// <summary>
+ /// The _configuration directory path
+ /// </summary>
+ private string _configurationDirectoryPath;
+ /// <summary>
+ /// Gets the path to the application configuration root directory
+ /// </summary>
+ /// <value>The configuration directory path.</value>
+ public string ConfigurationDirectoryPath
+ {
+ get
+ {
+ if (_configurationDirectoryPath == null)
+ {
+ _configurationDirectoryPath = Path.Combine(ProgramDataPath, "config");
+ if (!Directory.Exists(_configurationDirectoryPath))
+ {
+ Directory.CreateDirectory(_configurationDirectoryPath);
+ }
+ }
+ return _configurationDirectoryPath;
+ }
+ }
+
+ /// <summary>
+ /// The _system configuration file path
+ /// </summary>
+ private string _systemConfigurationFilePath;
+ /// <summary>
+ /// Gets the path to the system configuration file
+ /// </summary>
+ /// <value>The system configuration file path.</value>
+ public string SystemConfigurationFilePath
+ {
+ get
+ {
+ return _systemConfigurationFilePath ?? (_systemConfigurationFilePath = Path.Combine(ConfigurationDirectoryPath, "system.xml"));
+ }
+ }
+
+ /// <summary>
+ /// The _cache directory
+ /// </summary>
+ private string _cachePath;
+ /// <summary>
+ /// Gets the folder path to the cache directory
+ /// </summary>
+ /// <value>The cache directory.</value>
+ public string CachePath
+ {
+ get
+ {
+ if (_cachePath == null)
+ {
+ _cachePath = Path.Combine(ProgramDataPath, "cache");
+
+ if (!Directory.Exists(_cachePath))
+ {
+ Directory.CreateDirectory(_cachePath);
+ }
+ }
+
+ return _cachePath;
+ }
+ }
+
+ /// <summary>
+ /// The _temp directory
+ /// </summary>
+ private string _tempDirectory;
+ /// <summary>
+ /// Gets the folder path to the temp directory within the cache folder
+ /// </summary>
+ /// <value>The temp directory.</value>
+ public string TempDirectory
+ {
+ get
+ {
+ if (_tempDirectory == null)
+ {
+ _tempDirectory = Path.Combine(CachePath, "temp");
+
+ if (!Directory.Exists(_tempDirectory))
+ {
+ Directory.CreateDirectory(_tempDirectory);
+ }
+ }
+
+ return _tempDirectory;
+ }
+ }
+
+ /// <summary>
+ /// Gets the path to the application's ProgramDataFolder
+ /// </summary>
+ /// <returns>System.String.</returns>
+ public static string GetProgramDataPath()
+ {
+#if DEBUG
+ string programDataPath = ConfigurationManager.AppSettings["DebugProgramDataPath"];
+
+#else
+ string programDataPath = Path.Combine(ConfigurationManager.AppSettings["ReleaseProgramDataPath"], ConfigurationManager.AppSettings["ProgramDataFolderName"]);
+#endif
+
+ programDataPath = programDataPath.Replace("%CommonApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
+
+ // If it's a relative path, e.g. "..\"
+ if (!Path.IsPathRooted(programDataPath))
+ {
+ var path = Assembly.GetExecutingAssembly().Location;
+ path = Path.GetDirectoryName(path);
+
+ programDataPath = Path.Combine(path, programDataPath);
+
+ programDataPath = Path.GetFullPath(programDataPath);
+ }
+
+ if (!Directory.Exists(programDataPath))
+ {
+ Directory.CreateDirectory(programDataPath);
+ }
+
+ return programDataPath;
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
new file mode 100644
index 000000000..d271db060
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -0,0 +1,87 @@
+<?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>{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>MediaBrowser.Common.Implementations</RootNamespace>
+ <AssemblyName>MediaBrowser.Common.Implementations</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </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="protobuf-net">
+ <HintPath>..\packages\protobuf-net.2.0.0.621\lib\net40\protobuf-net.dll</HintPath>
+ </Reference>
+ <Reference Include="ServiceStack.Text">
+ <HintPath>..\packages\ServiceStack.Text.3.9.37\lib\net35\ServiceStack.Text.dll</HintPath>
+ </Reference>
+ <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="..\SharedVersion.cs">
+ <Link>Properties\SharedVersion.cs</Link>
+ </Compile>
+ <Compile Include="BaseApplicationPaths.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ScheduledTasks\TaskManager.cs" />
+ <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
+ <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
+ <Compile Include="ScheduledTasks\Tasks\ReloadLoggerTask.cs" />
+ <Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" />
+ <Compile Include="Serialization\JsonSerializer.cs" />
+ <Compile Include="Serialization\ProtobufSerializer.cs" />
+ <Compile Include="Serialization\XmlSerializer.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>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+ <Name>MediaBrowser.Model</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.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> \ No newline at end of file
diff --git a/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..f9c3e0bd1
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Properties/AssemblyInfo.cs
@@ -0,0 +1,31 @@
+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.Implementations")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MediaBrowser.Common.Implementations")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[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("fc7d85c6-0fe7-4db6-8158-54f7b18f17cd")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
new file mode 100644
index 000000000..c6eca29d1
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
@@ -0,0 +1,322 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Tasks;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks
+{
+ /// <summary>
+ /// Class TaskManager
+ /// </summary>
+ public class TaskManager : ITaskManager
+ {
+ /// <summary>
+ /// Gets the list of Scheduled Tasks
+ /// </summary>
+ /// <value>The scheduled tasks.</value>
+ public IScheduledTask[] ScheduledTasks { get; private set; }
+
+ /// <summary>
+ /// The _task queue
+ /// </summary>
+ private readonly List<Type> _taskQueue = new List<Type>();
+
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+
+ /// <summary>
+ /// The _application paths
+ /// </summary>
+ private readonly IApplicationPaths _applicationPaths;
+
+ /// <summary>
+ /// The _json serializer
+ /// </summary>
+ private readonly IJsonSerializer _jsonSerializer;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TaskManager" /> class.
+ /// </summary>
+ /// <param name="applicationPaths">The application paths.</param>
+ /// <param name="jsonSerializer">The json serializer.</param>
+ /// <param name="logger">The logger.</param>
+ /// <exception cref="System.ArgumentException">kernel</exception>
+ public TaskManager(IApplicationPaths applicationPaths, IJsonSerializer jsonSerializer, ILogger logger)
+ {
+ if (applicationPaths == null)
+ {
+ throw new ArgumentException("applicationPaths");
+ }
+ if (jsonSerializer == null)
+ {
+ throw new ArgumentException("jsonSerializer");
+ }
+ if (logger == null)
+ {
+ throw new ArgumentException("logger");
+ }
+
+ _applicationPaths = applicationPaths;
+ _jsonSerializer = jsonSerializer;
+ _logger = logger;
+
+ ScheduledTasks = new IScheduledTask[] {};
+ }
+
+ /// <summary>
+ /// Cancels if running and queue.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public void CancelIfRunningAndQueue<T>()
+ where T : IScheduledTask
+ {
+ ScheduledTasks.OfType<T>().First().CancelIfRunning();
+ QueueScheduledTask<T>();
+ }
+
+ /// <summary>
+ /// Queues the scheduled task.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public void QueueScheduledTask<T>()
+ where T : IScheduledTask
+ {
+ var scheduledTask = ScheduledTasks.OfType<T>().First();
+
+ QueueScheduledTask(scheduledTask);
+ }
+
+ /// <summary>
+ /// Queues the scheduled task.
+ /// </summary>
+ /// <param name="task">The task.</param>
+ public void QueueScheduledTask(IScheduledTask task)
+ {
+ var type = task.GetType();
+
+ var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
+
+ lock (_taskQueue)
+ {
+ // If it's idle just execute immediately
+ if (scheduledTask.State == TaskState.Idle)
+ {
+ scheduledTask.Execute();
+ return;
+ }
+
+ if (!_taskQueue.Contains(type))
+ {
+ _logger.Info("Queueing task {0}", type.Name);
+ _taskQueue.Add(type);
+ }
+ else
+ {
+ _logger.Info("Task already queued: {0}", type.Name);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Called when [task completed].
+ /// </summary>
+ /// <param name="task">The task.</param>
+ public void OnTaskCompleted(IScheduledTask task)
+ {
+ // Execute queued tasks
+ lock (_taskQueue)
+ {
+ var copy = _taskQueue.ToList();
+
+ foreach (var type in copy)
+ {
+ var scheduledTask = ScheduledTasks.First(t => t.GetType() == type);
+
+ if (scheduledTask.State == TaskState.Idle)
+ {
+ scheduledTask.Execute();
+
+ _taskQueue.Remove(type);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Adds the tasks.
+ /// </summary>
+ /// <param name="tasks">The tasks.</param>
+ public void AddTasks(IEnumerable<IScheduledTask> tasks)
+ {
+ var myTasks = ScheduledTasks.ToList();
+
+ myTasks.AddRange(tasks);
+
+ ScheduledTasks = myTasks.ToArray();
+ }
+
+ /// <summary>
+ /// The _scheduled tasks configuration directory
+ /// </summary>
+ private string _scheduledTasksConfigurationDirectory;
+ /// <summary>
+ /// Gets the scheduled tasks configuration directory.
+ /// </summary>
+ /// <value>The scheduled tasks configuration directory.</value>
+ private string ScheduledTasksConfigurationDirectory
+ {
+ get
+ {
+ if (_scheduledTasksConfigurationDirectory == null)
+ {
+ _scheduledTasksConfigurationDirectory = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "ScheduledTasks");
+
+ if (!Directory.Exists(_scheduledTasksConfigurationDirectory))
+ {
+ Directory.CreateDirectory(_scheduledTasksConfigurationDirectory);
+ }
+ }
+ return _scheduledTasksConfigurationDirectory;
+ }
+ }
+
+ /// <summary>
+ /// The _scheduled tasks data directory
+ /// </summary>
+ private string _scheduledTasksDataDirectory;
+ /// <summary>
+ /// Gets the scheduled tasks data directory.
+ /// </summary>
+ /// <value>The scheduled tasks data directory.</value>
+ private string ScheduledTasksDataDirectory
+ {
+ get
+ {
+ if (_scheduledTasksDataDirectory == null)
+ {
+ _scheduledTasksDataDirectory = Path.Combine(_applicationPaths.DataPath, "ScheduledTasks");
+
+ if (!Directory.Exists(_scheduledTasksDataDirectory))
+ {
+ Directory.CreateDirectory(_scheduledTasksDataDirectory);
+ }
+ }
+ return _scheduledTasksDataDirectory;
+ }
+ }
+
+ /// <summary>
+ /// Gets the history file path.
+ /// </summary>
+ /// <value>The history file path.</value>
+ private string GetHistoryFilePath(IScheduledTask task)
+ {
+ return Path.Combine(ScheduledTasksDataDirectory, task.Id + ".js");
+ }
+
+ /// <summary>
+ /// Gets the configuration file path.
+ /// </summary>
+ /// <param name="task">The task.</param>
+ /// <returns>System.String.</returns>
+ private string GetConfigurationFilePath(IScheduledTask task)
+ {
+ return Path.Combine(ScheduledTasksConfigurationDirectory, task.Id + ".js");
+ }
+
+ /// <summary>
+ /// Called when [task completed].
+ /// </summary>
+ /// <param name="task">The task.</param>
+ /// <param name="startTime">The start time.</param>
+ /// <param name="endTime">The end time.</param>
+ /// <param name="status">The status.</param>
+ public void OnTaskCompleted(IScheduledTask task, DateTime startTime, DateTime endTime, TaskCompletionStatus status)
+ {
+ var elapsedTime = endTime - startTime;
+
+ _logger.Info("{0} {1} after {2} minute(s) and {3} seconds", task.Name, status, Math.Truncate(elapsedTime.TotalMinutes), elapsedTime.Seconds);
+
+ var result = new TaskResult
+ {
+ StartTimeUtc = startTime,
+ EndTimeUtc = endTime,
+ Status = status,
+ Name = task.Name,
+ Id = task.Id
+ };
+
+ _jsonSerializer.SerializeToFile(result, GetHistoryFilePath(task));
+
+ //task.LastExecutionResult = result;
+ }
+
+ /// <summary>
+ /// Gets the last execution result.
+ /// </summary>
+ /// <param name="task">The task.</param>
+ /// <returns>TaskResult.</returns>
+ public TaskResult GetLastExecutionResult(IScheduledTask task)
+ {
+ return _jsonSerializer.DeserializeFromFile<TaskResult>(GetHistoryFilePath(task));
+ }
+
+ /// <summary>
+ /// Loads the triggers.
+ /// </summary>
+ /// <param name="task">The task.</param>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public IEnumerable<ITaskTrigger> LoadTriggers(IScheduledTask task)
+ {
+ try
+ {
+ return _jsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath(task))
+ .Select(ScheduledTaskHelpers.GetTrigger)
+ .ToList();
+ }
+ catch (IOException)
+ {
+ // File doesn't exist. No biggie. Return defaults.
+ return task.GetDefaultTriggers();
+ }
+ }
+
+ /// <summary>
+ /// Saves the triggers.
+ /// </summary>
+ /// <param name="task">The task.</param>
+ /// <param name="triggers">The triggers.</param>
+ public void SaveTriggers(IScheduledTask task, IEnumerable<ITaskTrigger> triggers)
+ {
+ _jsonSerializer.SerializeToFile(triggers.Select(ScheduledTaskHelpers.GetTriggerInfo), GetConfigurationFilePath(task));
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ foreach (var task in ScheduledTasks)
+ {
+ task.Dispose();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
new file mode 100644
index 000000000..2ef056658
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -0,0 +1,119 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Deletes old cache files
+ /// </summary>
+ public class DeleteCacheFileTask : BaseScheduledTask<IKernel>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
+ /// </summary>
+ /// <param name="kernel">The kernel.</param>
+ /// <param name="taskManager">The task manager.</param>
+ /// <param name="logger">The logger.</param>
+ public DeleteCacheFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
+ : base(kernel, taskManager, logger)
+ {
+ }
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+ {
+ var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
+
+ return new[] { trigger };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return Task.Run(() =>
+ {
+ var minDateModified = DateTime.UtcNow.AddMonths(-2);
+
+ DeleteCacheFilesFromDirectory(cancellationToken, Kernel.ApplicationPaths.CachePath, minDateModified, progress);
+ });
+ }
+
+
+ /// <summary>
+ /// Deletes the cache files from directory with a last write time less than a given date
+ /// </summary>
+ /// <param name="cancellationToken">The task cancellation token.</param>
+ /// <param name="directory">The directory.</param>
+ /// <param name="minDateModified">The min date modified.</param>
+ /// <param name="progress">The progress.</param>
+ private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
+ {
+ var filesToDelete = new DirectoryInfo(directory).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
+ .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && f.LastWriteTimeUtc < minDateModified)
+ .ToList();
+
+ var index = 0;
+
+ foreach (var file in filesToDelete)
+ {
+ double percent = index;
+ percent /= filesToDelete.Count;
+
+ progress.Report(100 * percent);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ File.Delete(file.FullName);
+
+ index++;
+ }
+
+ progress.Report(100);
+ }
+
+ /// <summary>
+ /// Gets the name of the task
+ /// </summary>
+ /// <value>The name.</value>
+ public override string Name
+ {
+ get { return "Cache file cleanup"; }
+ }
+
+ /// <summary>
+ /// Gets the description.
+ /// </summary>
+ /// <value>The description.</value>
+ public override string Description
+ {
+ get { return "Deletes cache files no longer needed by the system"; }
+ }
+
+ /// <summary>
+ /// Gets the category.
+ /// </summary>
+ /// <value>The category.</value>
+ public override string Category
+ {
+ get
+ {
+ return "Maintenance";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
new file mode 100644
index 000000000..dd00a7148
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
@@ -0,0 +1,107 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Deletes old log files
+ /// </summary>
+ public class DeleteLogFileTask : BaseScheduledTask<IKernel>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
+ /// </summary>
+ /// <param name="kernel">The kernel.</param>
+ /// <param name="taskManager">The task manager.</param>
+ /// <param name="logger">The logger.</param>
+ public DeleteLogFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
+ : base(kernel, taskManager, logger)
+ {
+ }
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+ {
+ var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }; //2am
+
+ return new[] { trigger };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return Task.Run(() =>
+ {
+ // Delete log files more than n days old
+ var minDateModified = DateTime.UtcNow.AddDays(-(Kernel.Configuration.LogFileRetentionDays));
+
+ var filesToDelete = new DirectoryInfo(Kernel.ApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
+ .Where(f => f.LastWriteTimeUtc < minDateModified)
+ .ToList();
+
+ var index = 0;
+
+ foreach (var file in filesToDelete)
+ {
+ double percent = index;
+ percent /= filesToDelete.Count;
+
+ progress.Report(100 * percent);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ File.Delete(file.FullName);
+
+ index++;
+ }
+
+ progress.Report(100);
+ });
+ }
+
+ /// <summary>
+ /// Gets the name of the task
+ /// </summary>
+ /// <value>The name.</value>
+ public override string Name
+ {
+ get { return "Log file cleanup"; }
+ }
+
+ /// <summary>
+ /// Gets the description.
+ /// </summary>
+ /// <value>The description.</value>
+ public override string Description
+ {
+ get { return string.Format("Deletes log files that are more than {0} days old.", Kernel.Configuration.LogFileRetentionDays); }
+ }
+
+ /// <summary>
+ /// Gets the category.
+ /// </summary>
+ /// <value>The category.</value>
+ public override string Category
+ {
+ get
+ {
+ return "Maintenance";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
new file mode 100644
index 000000000..79c633c76
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs
@@ -0,0 +1,71 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Class ReloadLoggerFileTask
+ /// </summary>
+ public class ReloadLoggerFileTask : BaseScheduledTask<IKernel>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ReloadLoggerFileTask" /> class.
+ /// </summary>
+ /// <param name="kernel">The kernel.</param>
+ /// <param name="taskManager">The task manager.</param>
+ /// <param name="logger">The logger.</param>
+ public ReloadLoggerFileTask(IKernel kernel, ITaskManager taskManager, ILogger logger)
+ : base(kernel, taskManager, logger)
+ {
+ }
+
+ /// <summary>
+ /// Gets the default triggers.
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+ {
+ var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(0) }; //12am
+
+ return new[] { trigger };
+ }
+
+ /// <summary>
+ /// Executes the internal.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ progress.Report(0);
+
+ return Task.Run(() => Kernel.ReloadLogger());
+ }
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public override string Name
+ {
+ get { return "Start new log file"; }
+ }
+
+ /// <summary>
+ /// Gets the description.
+ /// </summary>
+ /// <value>The description.</value>
+ public override string Description
+ {
+ get { return "Moves logging to a new file to help reduce log file sizes."; }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs
new file mode 100644
index 000000000..a101ad3dd
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/SystemUpdateTask.cs
@@ -0,0 +1,122 @@
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
+{
+ /// <summary>
+ /// Plugin Update Task
+ /// </summary>
+ public class SystemUpdateTask : BaseScheduledTask<IKernel>
+ {
+ /// <summary>
+ /// The _app host
+ /// </summary>
+ private readonly IApplicationHost _appHost;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SystemUpdateTask" /> class.
+ /// </summary>
+ /// <param name="appHost">The app host.</param>
+ /// <param name="taskManager">The task manager.</param>
+ /// <param name="kernel">The kernel.</param>
+ /// <param name="logger">The logger.</param>
+ public SystemUpdateTask(IApplicationHost appHost, ITaskManager taskManager, IKernel kernel, ILogger logger)
+ : base(kernel, taskManager, logger)
+ {
+ _appHost = appHost;
+ }
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public override IEnumerable<ITaskTrigger> GetDefaultTriggers()
+ {
+ return new ITaskTrigger[] {
+
+ // 1am
+ new DailyTrigger { TimeOfDay = TimeSpan.FromHours(1) },
+
+ new IntervalTrigger { Interval = TimeSpan.FromHours(2)}
+ };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ if (!_appHost.CanSelfUpdate) return;
+
+ EventHandler<double> innerProgressHandler = (sender, e) => progress.Report(e * .1);
+
+ // Create a progress object for the update check
+ var innerProgress = new Progress<double>();
+ innerProgress.ProgressChanged += innerProgressHandler;
+
+ var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false);
+
+ // Release the event handler
+ innerProgress.ProgressChanged -= innerProgressHandler;
+
+ progress.Report(10);
+
+ if (!updateInfo.IsUpdateAvailable)
+ {
+ progress.Report(100);
+ return;
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (Kernel.Configuration.EnableAutoUpdate)
+ {
+ Logger.Info("Update Revision {0} available. Updating...", updateInfo.AvailableVersion);
+
+ innerProgressHandler = (sender, e) => progress.Report((e * .9) + .1);
+
+ innerProgress = new Progress<double>();
+ innerProgress.ProgressChanged += innerProgressHandler;
+
+ await _appHost.UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false);
+
+ // Release the event handler
+ innerProgress.ProgressChanged -= innerProgressHandler;
+
+ Kernel.OnApplicationUpdated(updateInfo.AvailableVersion);
+ }
+ else
+ {
+ Logger.Info("A new version of Media Browser is available.");
+ }
+
+ progress.Report(100);
+ }
+
+ /// <summary>
+ /// Gets the name of the task
+ /// </summary>
+ /// <value>The name.</value>
+ public override string Name
+ {
+ get { return "Check for application updates"; }
+ }
+
+ /// <summary>
+ /// Gets the description.
+ /// </summary>
+ /// <value>The description.</value>
+ public override string Description
+ {
+ get { return "Downloads and installs application updates."; }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
new file mode 100644
index 000000000..bc8935a86
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
@@ -0,0 +1,240 @@
+using MediaBrowser.Model.Serialization;
+using System;
+using System.IO;
+
+namespace MediaBrowser.Common.Implementations.Serialization
+{
+ /// <summary>
+ /// Provides a wrapper around third party json serialization.
+ /// </summary>
+ public class JsonSerializer : IJsonSerializer
+ {
+ public JsonSerializer()
+ {
+ Configure();
+ }
+
+ /// <summary>
+ /// Serializes to stream.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <param name="stream">The stream.</param>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public void SerializeToStream<T>(T obj, Stream stream)
+ where T : class
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream);
+ }
+
+ /// <summary>
+ /// Serializes to file.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <param name="file">The file.</param>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public void SerializeToFile<T>(T obj, string file)
+ where T : class
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+
+ if (string.IsNullOrEmpty(file))
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ using (Stream stream = File.Open(file, FileMode.Create))
+ {
+ SerializeToStream(obj, stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from file.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="file">The file.</param>
+ /// <returns>System.Object.</returns>
+ /// <exception cref="System.ArgumentNullException">type</exception>
+ public object DeserializeFromFile(Type type, string file)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ if (string.IsNullOrEmpty(file))
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ using (Stream stream = File.OpenRead(file))
+ {
+ return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from file.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="file">The file.</param>
+ /// <returns>``0.</returns>
+ /// <exception cref="System.ArgumentNullException">file</exception>
+ public T DeserializeFromFile<T>(string file)
+ where T : class
+ {
+ if (string.IsNullOrEmpty(file))
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ using (Stream stream = File.OpenRead(file))
+ {
+ return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="stream">The stream.</param>
+ /// <returns>``0.</returns>
+ /// <exception cref="System.ArgumentNullException">stream</exception>
+ public T DeserializeFromStream<T>(Stream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ return ServiceStack.Text.JsonSerializer.DeserializeFromStream<T>(stream);
+ }
+
+ /// <summary>
+ /// Deserializes from string.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="text">The text.</param>
+ /// <returns>``0.</returns>
+ /// <exception cref="System.ArgumentNullException">text</exception>
+ public T DeserializeFromString<T>(string text)
+ {
+ if (string.IsNullOrEmpty(text))
+ {
+ throw new ArgumentNullException("text");
+ }
+
+ return ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(text);
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <param name="stream">The stream.</param>
+ /// <param name="type">The type.</param>
+ /// <returns>System.Object.</returns>
+ /// <exception cref="System.ArgumentNullException">stream</exception>
+ public object DeserializeFromStream(Stream stream, Type type)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ return ServiceStack.Text.JsonSerializer.DeserializeFromStream(type, stream);
+ }
+
+ /// <summary>
+ /// Configures this instance.
+ /// </summary>
+ private void Configure()
+ {
+ ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.JsonDateHandler.ISO8601;
+ ServiceStack.Text.JsConfig.ExcludeTypeInfo = true;
+ ServiceStack.Text.JsConfig.IncludeNullValues = false;
+ }
+
+ /// <summary>
+ /// Deserializes from string.
+ /// </summary>
+ /// <param name="json">The json.</param>
+ /// <param name="type">The type.</param>
+ /// <returns>System.Object.</returns>
+ /// <exception cref="System.ArgumentNullException">json</exception>
+ public object DeserializeFromString(string json, Type type)
+ {
+ if (string.IsNullOrEmpty(json))
+ {
+ throw new ArgumentNullException("json");
+ }
+
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ return ServiceStack.Text.JsonSerializer.DeserializeFromString(json, type);
+ }
+
+ /// <summary>
+ /// Serializes to string.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <returns>System.String.</returns>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public string SerializeToString<T>(T obj)
+ where T : class
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+
+ return ServiceStack.Text.JsonSerializer.SerializeToString(obj, obj.GetType());
+ }
+
+ /// <summary>
+ /// Serializes to bytes.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <returns>System.Byte[][].</returns>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public byte[] SerializeToBytes<T>(T obj)
+ where T : class
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+
+ using (var stream = new MemoryStream())
+ {
+ SerializeToStream(obj, stream);
+ return stream.ToArray();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs
new file mode 100644
index 000000000..85325f3c1
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Serialization/ProtobufSerializer.cs
@@ -0,0 +1,158 @@
+using MediaBrowser.Model.Serialization;
+using ProtoBuf;
+using ProtoBuf.Meta;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Common.Implementations.Serialization
+{
+ /// <summary>
+ /// Creates a compiled protobuf serializer based on a set of assemblies
+ /// </summary>
+ public class ProtobufSerializer : IProtobufSerializer
+ {
+ /// <summary>
+ /// Gets or sets the type model.
+ /// </summary>
+ /// <value>The type model.</value>
+ private TypeModel TypeModel { get; set; }
+
+ /// <summary>
+ /// Serializes to stream.
+ /// </summary>
+ /// <param name="obj">The obj.</param>
+ /// <param name="stream">The stream.</param>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public void SerializeToStream(object obj, Stream stream)
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ TypeModel.Serialize(stream, obj);
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <param name="stream">The stream.</param>
+ /// <param name="type">The type.</param>
+ /// <returns>System.Object.</returns>
+ /// <exception cref="System.ArgumentNullException">stream</exception>
+ public object DeserializeFromStream(Stream stream, Type type)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream");
+ }
+
+ return TypeModel.Deserialize(stream, null, type);
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="stream">The stream.</param>
+ /// <returns>``0.</returns>
+ public T DeserializeFromStream<T>(Stream stream)
+ where T : class
+ {
+ return DeserializeFromStream(stream, typeof(T)) as T;
+ }
+
+ /// <summary>
+ /// Serializes to file.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <param name="file">The file.</param>
+ /// <exception cref="System.ArgumentNullException">file</exception>
+ public void SerializeToFile<T>(T obj, string file)
+ {
+ if (string.IsNullOrEmpty(file))
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ using (Stream stream = File.Open(file, FileMode.Create))
+ {
+ SerializeToStream(obj, stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from file.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="file">The file.</param>
+ /// <returns>``0.</returns>
+ /// <exception cref="System.ArgumentNullException">file</exception>
+ public T DeserializeFromFile<T>(string file)
+ where T : class
+ {
+ if (string.IsNullOrEmpty(file))
+ {
+ throw new ArgumentNullException("file");
+ }
+
+ using (Stream stream = File.OpenRead(file))
+ {
+ return DeserializeFromStream<T>(stream);
+ }
+ }
+
+ /// <summary>
+ /// Serializes to bytes.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="obj">The obj.</param>
+ /// <returns>System.Byte[][].</returns>
+ /// <exception cref="System.ArgumentNullException">obj</exception>
+ public byte[] SerializeToBytes<T>(T obj)
+ where T : class
+ {
+ if (obj == null)
+ {
+ throw new ArgumentNullException("obj");
+ }
+
+ using (var stream = new MemoryStream())
+ {
+ SerializeToStream(obj, stream);
+ return stream.ToArray();
+ }
+ }
+
+ /// <summary>
+ /// Creates the specified assemblies.
+ /// </summary>
+ /// <returns>DynamicProtobufSerializer.</returns>
+ /// <exception cref="System.ArgumentNullException">assemblies</exception>
+ public static ProtobufSerializer Create(IEnumerable<Type> types)
+ {
+ if (types == null)
+ {
+ throw new ArgumentNullException("types");
+ }
+
+ var model = TypeModel.Create();
+ var attributeType = typeof(ProtoContractAttribute);
+
+ // Find all ProtoContracts in the current assembly
+ foreach (var type in types.Where(t => Attribute.IsDefined(t, attributeType)))
+ {
+ model.Add(type, true);
+ }
+
+ return new ProtobufSerializer { TypeModel = model.Compile() };
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
new file mode 100644
index 000000000..d01199f6f
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
@@ -0,0 +1,140 @@
+using MediaBrowser.Model.Serialization;
+using System;
+using System.IO;
+using System.Xml;
+
+namespace MediaBrowser.Common.Implementations.Serialization
+{
+ /// <summary>
+ /// Provides a wrapper around third party xml serialization.
+ /// </summary>
+ public class XmlSerializer : IXmlSerializer
+ {
+ /// <summary>
+ /// Serializes to writer.
+ /// </summary>
+ /// <param name="obj">The obj.</param>
+ /// <param name="writer">The writer.</param>
+ private void SerializeToWriter(object obj, XmlTextWriter writer)
+ {
+ writer.Formatting = Formatting.Indented;
+ var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
+ netSerializer.Serialize(writer, obj);
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="stream">The stream.</param>
+ /// <returns>``0.</returns>
+ public T DeserializeFromStream<T>(Stream stream)
+ {
+ using (var reader = new XmlTextReader(stream))
+ {
+ var netSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
+
+ return (T)netSerializer.Deserialize(reader);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from stream.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="stream">The stream.</param>
+ /// <returns>System.Object.</returns>
+ public object DeserializeFromStream(Type type, Stream stream)
+ {
+ using (var reader = new XmlTextReader(stream))
+ {
+ var netSerializer = new System.Xml.Serialization.XmlSerializer(type);
+
+ return netSerializer.Deserialize(reader);
+ }
+ }
+
+ /// <summary>
+ /// Serializes to stream.
+ /// </summary>
+ /// <param name="obj">The obj.</param>
+ /// <param name="stream">The stream.</param>
+ public void SerializeToStream(object obj, Stream stream)
+ {
+ using (var writer = new XmlTextWriter(stream, null))
+ {
+ SerializeToWriter(obj, writer);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from file.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="file">The file.</param>
+ /// <returns>``0.</returns>
+ public T DeserializeFromFile<T>(string file)
+ {
+ using (var stream = File.OpenRead(file))
+ {
+ return DeserializeFromStream<T>(stream);
+ }
+ }
+
+ /// <summary>
+ /// Serializes to file.
+ /// </summary>
+ /// <param name="obj">The obj.</param>
+ /// <param name="file">The file.</param>
+ public void SerializeToFile(object obj, string file)
+ {
+ using (var stream = new FileStream(file, FileMode.Create))
+ {
+ SerializeToStream(obj, stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from file.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="file">The file.</param>
+ /// <returns>System.Object.</returns>
+ public object DeserializeFromFile(Type type, string file)
+ {
+ using (var stream = File.OpenRead(file))
+ {
+ return DeserializeFromStream(type, stream);
+ }
+ }
+
+ /// <summary>
+ /// Deserializes from bytes.
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="buffer">The buffer.</param>
+ /// <returns>System.Object.</returns>
+ public object DeserializeFromBytes(Type type, byte[] buffer)
+ {
+ using (var stream = new MemoryStream(buffer))
+ {
+ return DeserializeFromStream(type, stream);
+ }
+ }
+
+ /// <summary>
+ /// Serializes to bytes.
+ /// </summary>
+ /// <param name="obj">The obj.</param>
+ /// <returns>System.Byte[][].</returns>
+ public byte[] SerializeToBytes(object obj)
+ {
+ using (var stream = new MemoryStream())
+ {
+ SerializeToStream(obj, stream);
+
+ return stream.ToArray();
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
new file mode 100644
index 000000000..14eb42cac
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="protobuf-net" version="2.0.0.621" targetFramework="net45" />
+ <package id="ServiceStack.Text" version="3.9.37" targetFramework="net45" />
+</packages> \ No newline at end of file