moved Plugins to separate repo

This commit is contained in:
LukePulverenti 2013-02-22 01:28:57 -05:00
parent 868a7ce9c8
commit 746c5d2fa7
54 changed files with 104 additions and 4693 deletions

View File

@ -141,7 +141,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetPluginAssembly request)
{
var plugin = Kernel.Plugins.First(p => p.UniqueId == request.Id);
var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
return ToStaticFileResult(plugin.AssemblyFilePath);
}
@ -153,7 +153,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetPluginConfiguration request)
{
var plugin = Kernel.Plugins.First(p => p.UniqueId == request.Id);
var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
var dateModified = plugin.ConfigurationDateLastModified;
@ -169,7 +169,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns>
public object Get(GetPluginConfigurationFile request)
{
var plugin = Kernel.Plugins.First(p => p.UniqueId == request.Id);
var plugin = Kernel.Plugins.First(p => p.Id == request.Id);
return ToStaticFileResult(plugin.ConfigurationFilePath);
}
@ -218,7 +218,7 @@ namespace MediaBrowser.Api
var pathInfo = PathInfo.Parse(Request.PathInfo);
var id = new Guid(pathInfo.GetArgumentValue<string>(1));
var plugin = Kernel.Plugins.First(p => p.UniqueId == id);
var plugin = Kernel.Plugins.First(p => p.Id == id);
var configuration = JsonSerializer.DeserializeFromStream(request.RequestStream, plugin.ConfigurationType) as BasePluginConfiguration;
@ -233,7 +233,7 @@ namespace MediaBrowser.Api
{
var kernel = (Kernel)Kernel;
var plugin = kernel.Plugins.First(p => p.UniqueId == request.Id);
var plugin = kernel.Plugins.First(p => p.Id == request.Id);
kernel.InstallationManager.UninstallPlugin(plugin);
}

View File

@ -382,15 +382,15 @@ var ApiClient = {
/**
* Gets the configuration of a plugin
* @param {String} uniqueId
* @param {String} Id
*/
getPluginConfiguration: function (uniqueId) {
getPluginConfiguration: function (id) {
if (!uniqueId) {
throw new Error("null uniqueId");
if (!id) {
throw new Error("null Id");
}
var url = ApiClient.getUrl("Plugins/" + uniqueId + "/Configuration");
var url = ApiClient.getUrl("Plugins/" + id + "/Configuration");
return $.getJSON(url);
},
@ -407,15 +407,15 @@ var ApiClient = {
/**
* Uninstalls a plugin
* @param {String} uniqueId
* @param {String} Id
*/
uninstallPlugin: function (uniqueId) {
uninstallPlugin: function (id) {
if (!uniqueId) {
throw new Error("null uniqueId");
if (!id) {
throw new Error("null Id");
}
var url = ApiClient.getUrl("Plugins/" + uniqueId);
var url = ApiClient.getUrl("Plugins/" + id);
return $.ajax({
type: "DELETE",
@ -1207,20 +1207,20 @@ var ApiClient = {
/**
* Updates a plugin's configuration
* @param {String} uniqueId
* @param {String} Id
* @param {Object} configuration
*/
updatePluginConfiguration: function (uniqueId, configuration) {
updatePluginConfiguration: function (id, configuration) {
if (!uniqueId) {
throw new Error("null uniqueId");
if (!id) {
throw new Error("null Id");
}
if (!configuration) {
throw new Error("null configuration");
}
var url = ApiClient.getUrl("Plugins/" + uniqueId + "/Configuration");
var url = ApiClient.getUrl("Plugins/" + id + "/Configuration");
return $.post(url, JSON.stringify(configuration));
},

View File

@ -362,7 +362,7 @@ namespace MediaBrowser.ApiInteraction
throw new ArgumentNullException("plugin");
}
var url = GetApiUrl("Plugins/" + plugin.UniqueId + "/Assembly");
var url = GetApiUrl("Plugins/" + plugin.Id + "/Assembly");
return HttpClient.GetStreamAsync(url, Logger, CancellationToken.None);
}

View File

@ -90,7 +90,7 @@ namespace MediaBrowser.Common.Plugins
/// Gets the unique id.
/// </summary>
/// <value>The unique id.</value>
public Guid UniqueId
public Guid Id
{
get
{
@ -419,7 +419,7 @@ namespace MediaBrowser.Common.Plugins
ConfigurationDateLastModified = ConfigurationDateLastModified,
Description = Description,
IsCorePlugin = IsCorePlugin,
UniqueId = UniqueId,
Id = Id,
EnableAutoUpdate = Configuration.EnableAutoUpdate,
UpdateClass = Configuration.UpdateClass,
ConfigurationFileName = ConfigurationFileName

View File

@ -35,7 +35,7 @@ namespace MediaBrowser.Common.Plugins
/// Gets the unique id.
/// </summary>
/// <value>The unique id.</value>
Guid UniqueId { get; }
Guid Id { get; }
/// <summary>
/// Gets the plugin version

View File

@ -182,8 +182,8 @@ namespace MediaBrowser.Controller
/// Gets the list of plugin configuration pages
/// </summary>
/// <value>The configuration pages.</value>
[ImportMany(typeof(BaseConfigurationPage))]
public IEnumerable<BaseConfigurationPage> PluginConfigurationPages { get; private set; }
[ImportMany(typeof(IPluginConfigurationPage))]
public IEnumerable<IPluginConfigurationPage> PluginConfigurationPages { get; private set; }
/// <summary>
/// Gets the intro providers.

View File

@ -128,7 +128,7 @@
<Compile Include="Persistence\IUserRepository.cs" />
<Compile Include="Persistence\TypeMapper.cs" />
<Compile Include="Playback\IIntroProvider.cs" />
<Compile Include="Plugins\BaseConfigurationPage.cs" />
<Compile Include="Plugins\IPluginConfigurationPage.cs" />
<Compile Include="Plugins\PluginSecurityManager.cs" />
<Compile Include="Providers\FanartBaseProvider.cs" />
<Compile Include="Providers\BaseImageEnhancer.cs" />

View File

@ -1,81 +0,0 @@
using MediaBrowser.Common.Plugins;
using System.IO;
namespace MediaBrowser.Controller.Plugins
{
/// <summary>
/// Class BaseConfigurationPage
/// </summary>
public abstract class BaseConfigurationPage
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public abstract string Name { get; }
/// <summary>
/// Gets the description.
/// </summary>
/// <value>The description.</value>
public virtual string Description
{
get { return string.Empty; }
}
/// <summary>
/// Gets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
public virtual ConfigurationPageType ConfigurationPageType
{
get { return ConfigurationPageType.PluginConfiguration; }
}
/// <summary>
/// Gets the HTML stream from manifest resource.
/// </summary>
/// <param name="resource">The resource.</param>
/// <returns>Stream.</returns>
protected Stream GetHtmlStreamFromManifestResource(string resource)
{
return GetType().Assembly.GetManifestResourceStream(resource);
}
/// <summary>
/// Gets the HTML stream.
/// </summary>
/// <returns>Stream.</returns>
public abstract Stream GetHtmlStream();
/// <summary>
/// Gets the name of the plugin.
/// </summary>
/// <value>The name of the plugin.</value>
public virtual string OwnerPluginName
{
get { return GetOwnerPlugin().Name; }
}
/// <summary>
/// Gets the owner plugin.
/// </summary>
/// <returns>BasePlugin.</returns>
public abstract IPlugin GetOwnerPlugin();
}
/// <summary>
/// Enum ConfigurationPageType
/// </summary>
public enum ConfigurationPageType
{
/// <summary>
/// The plugin configuration
/// </summary>
PluginConfiguration,
/// <summary>
/// The none
/// </summary>
None
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.IO;
namespace MediaBrowser.Controller.Plugins
{
/// <summary>
/// Interface IConfigurationPage
/// </summary>
public interface IPluginConfigurationPage
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Gets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
ConfigurationPageType ConfigurationPageType { get; }
/// <summary>
/// Gets the plugin id.
/// </summary>
/// <value>The plugin id.</value>
Guid? PluginId { get; }
/// <summary>
/// Gets the HTML stream.
/// </summary>
/// <returns>Stream.</returns>
Stream GetHtmlStream();
/// <summary>
/// Gets the version. Typically taken from Plugin.Version
/// </summary>
/// <value>The version.</value>
string Version { get; }
/// <summary>
/// For http caching purposes. Typically taken from Plugin.AssemblyDateLastModified
/// </summary>
DateTime DateLastModified { get; }
}
/// <summary>
/// Enum ConfigurationPageType
/// </summary>
public enum ConfigurationPageType
{
/// <summary>
/// The plugin configuration
/// </summary>
PluginConfiguration,
/// <summary>
/// The none
/// </summary>
None
}
}

View File

@ -71,7 +71,7 @@ namespace MediaBrowser.Model.Plugins
/// </summary>
/// <value>The unique id.</value>
[ProtoMember(9)]
public Guid UniqueId { get; set; }
public Guid Id { get; set; }
/// <summary>
/// Whether or not this plug-in should be automatically updated when a

View File

@ -1,50 +0,0 @@
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller.Plugins;
using System.ComponentModel.Composition;
using System.IO;
namespace MediaBrowser.Plugins.Dlna.Configuration
{
/// <summary>
/// Class DlnaConfigurationPage
/// </summary>
[Export(typeof(BaseConfigurationPage))]
class DlnaConfigurationPage : BaseConfigurationPage
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "Dlna"; }
}
/// <summary>
/// Gets the HTML stream.
/// </summary>
/// <returns>Stream.</returns>
public override Stream GetHtmlStream()
{
return GetHtmlStreamFromManifestResource("MediaBrowser.Plugins.Dlna.Configuration.configPage.html");
}
/// <summary>
/// Gets the owner plugin.
/// </summary>
/// <returns>BasePlugin.</returns>
public override IPlugin GetOwnerPlugin()
{
return Plugin.Instance;
}
/// <summary>
/// Gets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
public override ConfigurationPageType ConfigurationPageType
{
get { return ConfigurationPageType.PluginConfiguration; }
}
}
}

View File

@ -1,39 +0,0 @@
using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Plugins.Dlna.Configuration
{
/// <summary>
/// Class PluginConfiguration
/// </summary>
public class PluginConfiguration : BasePluginConfiguration
{
/// <summary>
/// Gets or sets the friendly name of the DLNA Server.
/// </summary>
/// <value>The friendly name of the DLNA Server.</value>
public string FriendlyDlnaName { get; set; }
/// <summary>
/// Gets or sets the Port Number for the DLNA Server.
/// </summary>
/// <value>The Port Number of the DLNA Server.</value>
public short? DlnaPortNumber { get; set; }
/// <summary>
/// Gets or sets the name of the user to impersonate.
/// </summary>
/// <value>The name of the User.</value>
public string UserName { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="PluginConfiguration" /> class.
/// </summary>
public PluginConfiguration()
: base()
{
//this.DlnaPortNumber = 1845;
this.FriendlyDlnaName = "MB3 UPnP";
this.UserName = string.Empty;
}
}
}

View File

@ -1,92 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>dlna</title>
</head>
<body>
<div id="dlnaConfigurationPage" data-role="page" class="page type-interior pluginConfigurationPage">
<div data-role="content">
<div class="content-primary">
<form id="dlnaConfigurationForm">
<ul class="ulForm" data-role="listview">
<li>
<label for="txtUserName">
User name:
</label>
<input id="txtUserName" name="txtUserName" />
</li>
<li>
<label for="txtFriendlyDlnaName">
Friendly Dlna Server Name:
</label>
<input id="txtFriendlyDlnaName" name="txtFriendlyDlnaName" />
</li>
<li>
<label for="txtDlnaPortNumber">
Dlna Server Port:
</label>
<input type="number" id="txtDlnaPortNumber" name="txtDlnaPortNumber" pattern="[0-9]*" min="1" />
<div class="fieldDescription">
If specified, the Dlna server will use this port
</div>
</li>
<li>
<button type="submit" data-theme="b">Save</button>
<div class="fieldDescription">
Saving will restart the dlna server.
</div>
<button type="button" onclick="history.back();">Cancel</button>
</li>
</ul>
</form>
</div>
</div>
<script type="text/javascript">
var dlnaConfigurationPage = {
pluginUniqueId: "f1855371-7cf5-40d2-bcd8-b780d7f006af"
};
$('#dlnaConfigurationPage').on('pageshow', function (event) {
Dashboard.showLoadingMsg();
var page = this;
ApiClient.getPluginConfiguration(dlnaConfigurationPage.pluginUniqueId).done(function (config) {
$('#txtUserName', page).val(config.UserName);
$('#txtFriendlyDlnaName', page).val(config.FriendlyDlnaName);
$('#txtDlnaPortNumber', page).val(config.DlnaPortNumber || "");
Dashboard.hideLoadingMsg();
});
});
$('#dlnaConfigurationForm').on('submit', function (e) {
Dashboard.showLoadingMsg();
var form = this;
ApiClient.getPluginConfiguration(dlnaConfigurationPage.pluginUniqueId).done(function (config) {
config.UserName = $('#txtUserName', form).val();
config.FriendlyDlnaName = $('#txtFriendlyDlnaName', form).val();
var dlnaPortNumber = $('#txtDlnaPortNumber', form).val();
config.DlnaPortNumber = dlnaPortNumber ? dlnaPortNumber : null;
ApiClient.updatePluginConfiguration(dlnaConfigurationPage.pluginUniqueId, config).done(Dashboard.processPluginConfigurationUpdateResult);
});
// Disable default form submission
return false;
});
</script>
</div>
</body>
</html>

View File

@ -1,91 +0,0 @@
<?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>{A2CF4266-2110-419E-8620-E2FEEFCA0F48}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Plugins.Dlna</RootNamespace>
<AssemblyName>MediaBrowser.Plugins.Dlna</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>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</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>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="Platinum.Managed">
<HintPath>..\ThirdParty\UPnP\Libs\Platinum.Managed.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<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\DlnaConfigurationPage.cs" />
<Compile Include="Configuration\PluginConfiguration.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>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\ThirdParty\UPnP\Libs\Platinum.Managed.dll">
<Link>Assemblies\Platinum.Managed.dll</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="..\ThirdParty\UPnP\Libs\log4net.dll">
<Link>Assemblies\log4net.dll</Link>
</Content>
<EmbeddedResource Include="Configuration\configPage.html" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData-Server\Plugins\" /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>

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
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.Plugins.Dlna")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.Plugins.Dlna")]
[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("f1855371-7cf5-40d2-bcd8-b780d7f006af")]
// 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.*")]

View File

@ -1,109 +0,0 @@
<?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>{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}</ProjectGuid>
<OutputType>library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Plugins.MpcHc</RootNamespace>
<AssemblyName>MediaBrowser.Plugins.MpcHc</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<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>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="MpcHcMediaPlayer.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</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>
<ProjectReference Include="..\MediaBrowser.UI\MediaBrowser.UI.csproj">
<Project>{b5ece1fb-618e-420b-9a99-8e972d76920a}</Project>
<Name>MediaBrowser.UI</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData-Server\Plugins\" /y</PostBuildEvent>
</PropertyGroup>
<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>

View File

@ -1,580 +0,0 @@
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.UI.Configuration;
using MediaBrowser.UI.Controller;
using MediaBrowser.UI.Playback;
using MediaBrowser.UI.Playback.ExternalPlayer;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Plugins.MpcHc
{
/// <summary>
/// Class GenericExternalPlayer
/// </summary>
[Export(typeof(BaseMediaPlayer))]
public class MpcHcMediaPlayer : BaseExternalPlayer
{
/// <summary>
/// The state sync lock
/// </summary>
private object stateSyncLock = new object();
/// <summary>
/// The MPC HTTP interface resource pool
/// </summary>
private SemaphoreSlim MpcHttpInterfaceResourcePool = new SemaphoreSlim(1, 1);
[ImportingConstructor]
public MpcHcMediaPlayer([Import("logger")] ILogger logger)
: base(logger)
{
}
/// <summary>
/// Gets or sets the HTTP interface cancellation token.
/// </summary>
/// <value>The HTTP interface cancellation token.</value>
private CancellationTokenSource HttpInterfaceCancellationTokenSource { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has started playing.
/// </summary>
/// <value><c>true</c> if this instance has started playing; otherwise, <c>false</c>.</value>
private bool HasStartedPlaying { get; set; }
/// <summary>
/// Gets or sets the status update timer.
/// </summary>
/// <value>The status update timer.</value>
private Timer StatusUpdateTimer { get; set; }
/// <summary>
/// Gets a value indicating whether this instance can monitor progress.
/// </summary>
/// <value><c>true</c> if this instance can monitor progress; otherwise, <c>false</c>.</value>
protected override bool CanMonitorProgress
{
get
{
return true;
}
}
/// <summary>
/// The _current position ticks
/// </summary>
private long? _currentPositionTicks;
/// <summary>
/// Gets the current position ticks.
/// </summary>
/// <value>The current position ticks.</value>
public override long? CurrentPositionTicks
{
get
{
return _currentPositionTicks;
}
}
/// <summary>
/// The _current playlist index
/// </summary>
private int _currentPlaylistIndex;
/// <summary>
/// Gets the index of the current playlist.
/// </summary>
/// <value>The index of the current playlist.</value>
public override int CurrentPlaylistIndex
{
get
{
return _currentPlaylistIndex;
}
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "MpcHc"; }
}
/// <summary>
/// Gets a value indicating whether this instance can close automatically.
/// </summary>
/// <value><c>true</c> if this instance can close automatically; otherwise, <c>false</c>.</value>
protected override bool CanCloseAutomatically
{
get
{
return true;
}
}
/// <summary>
/// Determines whether this instance can play the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if this instance can play the specified item; otherwise, <c>false</c>.</returns>
public override bool CanPlay(BaseItemDto item)
{
return item.IsVideo || item.IsAudio;
}
/// <summary>
/// Gets the command arguments.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="options">The options.</param>
/// <param name="playerConfiguration">The player configuration.</param>
/// <returns>System.String.</returns>
protected override string GetCommandArguments(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
{
var formatString = "{0} /play /fullscreen /close";
var firstItem = items[0];
var startTicks = Math.Max(options.StartPositionTicks, 0);
if (startTicks > 0 && firstItem.IsVideo && firstItem.VideoType.HasValue && firstItem.VideoType.Value == VideoType.Dvd)
{
formatString += " /dvdpos 1#" + TimeSpan.FromTicks(startTicks).ToString("hh\\:mm\\:ss");
}
else
{
formatString += " /start " + TimeSpan.FromTicks(startTicks).TotalMilliseconds;
}
return GetCommandArguments(items, formatString);
}
/// <summary>
/// Gets the path for command line.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
protected override string GetPathForCommandLine(BaseItemDto item)
{
var path = base.GetPathForCommandLine(item);
if (item.IsVideo && item.VideoType.HasValue)
{
if (item.VideoType.Value == VideoType.Dvd)
{
// Point directly to the video_ts path
// Otherwise mpc will play any other media files that might exist in the dvd top folder (e.g. video backdrops).
var videoTsPath = Path.Combine(path, "video_ts");
if (Directory.Exists(videoTsPath))
{
path = videoTsPath;
}
}
if (item.VideoType.Value == VideoType.BluRay)
{
// Point directly to the bdmv path
var bdmvPath = Path.Combine(path, "bdmv");
if (Directory.Exists(bdmvPath))
{
path = bdmvPath;
}
}
}
return FormatPath(path);
}
/// <summary>
/// Formats the path.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>System.String.</returns>
private string FormatPath(string path)
{
if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase))
{
path = path.TrimEnd('\\');
}
return path;
}
/// <summary>
/// Called when [external player launched].
/// </summary>
protected override void OnExternalPlayerLaunched()
{
base.OnExternalPlayerLaunched();
ReloadStatusUpdateTimer();
}
/// <summary>
/// Reloads the status update timer.
/// </summary>
private void ReloadStatusUpdateTimer()
{
DisposeStatusTimer();
HttpInterfaceCancellationTokenSource = new CancellationTokenSource();
StatusUpdateTimer = new Timer(OnStatusUpdateTimerStopped, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
}
/// <summary>
/// Called when [status update timer stopped].
/// </summary>
/// <param name="state">The state.</param>
private async void OnStatusUpdateTimerStopped(object state)
{
try
{
var token = HttpInterfaceCancellationTokenSource.Token;
using (var stream = await UIKernel.Instance.HttpManager.Get(StatusUrl, MpcHttpInterfaceResourcePool, token).ConfigureAwait(false))
{
token.ThrowIfCancellationRequested();
using (var reader = new StreamReader(stream))
{
token.ThrowIfCancellationRequested();
var result = await reader.ReadToEndAsync().ConfigureAwait(false);
token.ThrowIfCancellationRequested();
ProcessStatusResult(result);
}
}
}
catch (HttpRequestException ex)
{
Logger.ErrorException("Error connecting to MpcHc status interface", ex);
}
catch (OperationCanceledException)
{
// Manually cancelled by us
Logger.Info("Status request cancelled");
}
}
/// <summary>
/// Processes the status result.
/// </summary>
/// <param name="result">The result.</param>
private async void ProcessStatusResult(string result)
{
// Sample result
// OnStatus('test.avi', 'Playing', 5292, '00:00:05', 1203090, '00:20:03', 0, 100, 'C:\test.avi')
// 5292 = position in ms
// 00:00:05 = position
// 1203090 = duration in ms
// 00:20:03 = duration
var quoteChar = result.IndexOf(", \"", StringComparison.OrdinalIgnoreCase) == -1 ? '\'' : '\"';
// Strip off the leading "OnStatus(" and the trailing ")"
result = result.Substring(result.IndexOf(quoteChar));
result = result.Substring(0, result.LastIndexOf(quoteChar));
// Strip off the filename at the beginning
result = result.Substring(result.IndexOf(string.Format("{0}, {0}", quoteChar), StringComparison.OrdinalIgnoreCase) + 3);
// Find the last index of ", '" so that we can extract and then strip off the file path at the end.
var lastIndexOfSeparator = result.LastIndexOf(", " + quoteChar, StringComparison.OrdinalIgnoreCase);
// Get the current playing file path
var currentPlayingFile = result.Substring(lastIndexOfSeparator + 2).Trim(quoteChar);
// Strip off the current playing file path
result = result.Substring(0, lastIndexOfSeparator);
var values = result.Split(',').Select(v => v.Trim().Trim(quoteChar)).ToList();
var currentPositionTicks = TimeSpan.FromMilliseconds(double.Parse(values[1])).Ticks;
//var currentDurationTicks = TimeSpan.FromMilliseconds(double.Parse(values[3])).Ticks;
var playstate = values[0];
var playlistIndex = GetPlaylistIndex(currentPlayingFile);
if (playstate.Equals("stopped", StringComparison.OrdinalIgnoreCase))
{
if (HasStartedPlaying)
{
await ClosePlayer().ConfigureAwait(false);
}
}
else
{
lock (stateSyncLock)
{
if (_currentPlaylistIndex != playlistIndex)
{
OnMediaChanged(_currentPlaylistIndex, _currentPositionTicks, playlistIndex);
}
_currentPositionTicks = currentPositionTicks;
_currentPlaylistIndex = playlistIndex;
}
if (playstate.Equals("playing", StringComparison.OrdinalIgnoreCase))
{
HasStartedPlaying = true;
PlayState = PlayState.Playing;
}
else if (playstate.Equals("paused", StringComparison.OrdinalIgnoreCase))
{
HasStartedPlaying = true;
PlayState = PlayState.Paused;
}
}
}
/// <summary>
/// Gets the index of the playlist.
/// </summary>
/// <param name="nowPlayingPath">The now playing path.</param>
/// <returns>System.Int32.</returns>
private int GetPlaylistIndex(string nowPlayingPath)
{
for (var i = 0; i < Playlist.Count; i++)
{
var item = Playlist[i];
var pathArg = GetPathForCommandLine(item);
if (pathArg.Equals(nowPlayingPath, StringComparison.OrdinalIgnoreCase))
{
return i;
}
if (item.VideoType.HasValue)
{
if (item.VideoType.Value == VideoType.BluRay || item.VideoType.Value == VideoType.Dvd || item.VideoType.Value == VideoType.HdDvd)
{
if (nowPlayingPath.StartsWith(pathArg, StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
}
}
return -1;
}
/// <summary>
/// Called when [player stopped internal].
/// </summary>
protected override void OnPlayerStoppedInternal()
{
HttpInterfaceCancellationTokenSource.Cancel();
DisposeStatusTimer();
_currentPositionTicks = null;
_currentPlaylistIndex = 0;
HasStartedPlaying = false;
HttpInterfaceCancellationTokenSource = null;
base.OnPlayerStoppedInternal();
}
/// <summary>
/// Disposes the status timer.
/// </summary>
private void DisposeStatusTimer()
{
if (StatusUpdateTimer != null)
{
StatusUpdateTimer.Dispose();
}
}
/// <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 override void Dispose(bool dispose)
{
if (dispose)
{
DisposeStatusTimer();
MpcHttpInterfaceResourcePool.Dispose();
}
base.Dispose(dispose);
}
/// <summary>
/// Seeks the internal.
/// </summary>
/// <param name="positionTicks">The position ticks.</param>
/// <returns>Task.</returns>
protected override Task SeekInternal(long positionTicks)
{
var additionalParams = new Dictionary<string, string>();
var time = TimeSpan.FromTicks(positionTicks);
var timeString = time.Hours + ":" + time.Minutes + ":" + time.Seconds;
additionalParams.Add("position", timeString);
return SendCommandToPlayer("-1", additionalParams);
}
/// <summary>
/// Pauses the internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task PauseInternal()
{
return SendCommandToPlayer("888", new Dictionary<string, string>());
}
/// <summary>
/// Uns the pause internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task UnPauseInternal()
{
return SendCommandToPlayer("887", new Dictionary<string, string>());
}
/// <summary>
/// Stops the internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task StopInternal()
{
return SendCommandToPlayer("890", new Dictionary<string, string>());
}
/// <summary>
/// Closes the player.
/// </summary>
/// <returns>Task.</returns>
protected Task ClosePlayer()
{
return SendCommandToPlayer("816", new Dictionary<string, string>());
}
/// <summary>
/// Sends a command to MPC using the HTTP interface
/// http://www.autohotkey.net/~specter333/MPC/HTTP%20Commands.txt
/// </summary>
/// <param name="commandNumber">The command number.</param>
/// <param name="additionalParams">The additional params.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">commandNumber</exception>
private async Task SendCommandToPlayer(string commandNumber, Dictionary<string, string> additionalParams)
{
if (string.IsNullOrEmpty(commandNumber))
{
throw new ArgumentNullException("commandNumber");
}
if (additionalParams == null)
{
throw new ArgumentNullException("additionalParams");
}
var url = CommandUrl + "?wm_command=" + commandNumber;
url = additionalParams.Keys.Aggregate(url, (current, name) => current + ("&" + name + "=" + additionalParams[name]));
Logger.Info("Sending command to MPC: " + url);
try
{
using (var stream = await UIKernel.Instance.HttpManager.Get(url, MpcHttpInterfaceResourcePool, HttpInterfaceCancellationTokenSource.Token).ConfigureAwait(false))
{
}
}
catch (HttpRequestException ex)
{
Logger.ErrorException("Error connecting to MpcHc command interface", ex);
}
catch (OperationCanceledException)
{
// Manually cancelled by us
Logger.Info("Command request cancelled");
}
}
/// <summary>
/// Gets a value indicating whether this instance can pause.
/// </summary>
/// <value><c>true</c> if this instance can pause; otherwise, <c>false</c>.</value>
public override bool CanPause
{
get
{
return true;
}
}
/// <summary>
/// Gets the server name that the http interface will be running on
/// </summary>
/// <value>The HTTP server.</value>
private string HttpServer
{
get
{
return "localhost";
}
}
/// <summary>
/// Gets the port that the web interface will be running on
/// </summary>
/// <value>The HTTP port.</value>
private string HttpPort
{
get
{
return "13579";
}
}
/// <summary>
/// Gets the url of that will be called to for status
/// </summary>
/// <value>The status URL.</value>
private string StatusUrl
{
get
{
return "http://" + HttpServer + ":" + HttpPort + "/status.html";
}
}
/// <summary>
/// Gets the url of that will be called to send commands
/// </summary>
/// <value>The command URL.</value>
private string CommandUrl
{
get
{
return "http://" + HttpServer + ":" + HttpPort + "/command.html";
}
}
}
}

View File

@ -1,32 +0,0 @@
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using System;
using System.ComponentModel.Composition;
namespace MediaBrowser.Plugins.MpcHc
{
/// <summary>
/// Class Plugin
/// </summary>
[Export(typeof(IPlugin))]
public class Plugin : BaseUiPlugin<BasePluginConfiguration>
{
/// <summary>
/// Gets the name of the plugin
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "MPC-HC Integration"; }
}
/// <summary>
/// Gets the minimum required UI version.
/// </summary>
/// <value>The minimum required UI version.</value>
public override Version MinimumRequiredUIVersion
{
get { return new Version("2.9.4782.23738"); }
}
}
}

View File

@ -1,53 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
// 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.Plugins.MpcHc")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.Plugins.MpcHc")]
[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)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
[assembly: Guid("F6D17656-25FE-4564-9246-B4584F797348")]
// 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.*")]

View File

@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.Plugins.MpcHc.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MediaBrowser.Plugins.MpcHc.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.Plugins.MpcHc.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -1,108 +0,0 @@
<?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>{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}</ProjectGuid>
<OutputType>library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Plugins.Tmt5</RootNamespace>
<AssemblyName>MediaBrowser.Plugins.Tmt5</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<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>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="Tmt5MediaPlayer.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</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>
<ProjectReference Include="..\MediaBrowser.UI\MediaBrowser.UI.csproj">
<Project>{b5ece1fb-618e-420b-9a99-8e972d76920a}</Project>
<Name>MediaBrowser.UI</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData-Server\Plugins\" /y</PostBuildEvent>
</PropertyGroup>
<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>

View File

@ -1,32 +0,0 @@
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using System;
using System.ComponentModel.Composition;
namespace MediaBrowser.Plugins.Tmt5
{
/// <summary>
/// Class Plugin
/// </summary>
[Export(typeof(IPlugin))]
public class Plugin : BaseUiPlugin<BasePluginConfiguration>
{
/// <summary>
/// Gets the name of the plugin
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "TMT5 Integration"; }
}
/// <summary>
/// Gets the minimum required UI version.
/// </summary>
/// <value>The minimum required UI version.</value>
public override Version MinimumRequiredUIVersion
{
get { return new Version("2.9.4782.23738"); }
}
}
}

View File

@ -1,53 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
// 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.Plugins.Tmt5")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.Plugins.Tmt5")]
[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)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
[assembly: Guid("3921C21B-B8C0-46C2-92DE-CC0E1FE0C434")]
// 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.*")]

View File

@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.Plugins.Tmt5.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MediaBrowser.Plugins.Tmt5.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MediaBrowser.Plugins.Tmt5.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -1,405 +0,0 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Logging;
using MediaBrowser.UI.Configuration;
using MediaBrowser.UI.Playback;
using MediaBrowser.UI.Playback.ExternalPlayer;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
namespace MediaBrowser.Plugins.Tmt5
{
/// <summary>
/// Class GenericExternalPlayer
/// </summary>
[Export(typeof(BaseMediaPlayer))]
public class Tmt5MediaPlayer : BaseExternalPlayer
{
[ImportingConstructor]
public Tmt5MediaPlayer([Import("logger")] ILogger logger)
: base(logger)
{
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "TMT5"; }
}
/// <summary>
/// Gets a value indicating whether this instance can pause.
/// </summary>
/// <value><c>true</c> if this instance can pause; otherwise, <c>false</c>.</value>
public override bool CanPause
{
get
{
return true;
}
}
/// <summary>
/// Gets a value indicating whether this instance can close automatically.
/// </summary>
/// <value><c>true</c> if this instance can close automatically; otherwise, <c>false</c>.</value>
protected override bool CanCloseAutomatically
{
get
{
return true;
}
}
/// <summary>
/// Gets the play state directory.
/// </summary>
/// <value>The play state directory.</value>
private string PlayStateDirectory
{
get
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ArcSoft");
}
}
/// <summary>
/// The _current position ticks
/// </summary>
private long? _currentPositionTicks;
/// <summary>
/// Gets the current position ticks.
/// </summary>
/// <value>The current position ticks.</value>
public override long? CurrentPositionTicks
{
get
{
return _currentPositionTicks;
}
}
/// <summary>
/// The _current playlist index
/// </summary>
private int _currentPlaylistIndex;
/// <summary>
/// Gets the index of the current playlist.
/// </summary>
/// <value>The index of the current playlist.</value>
public override int CurrentPlaylistIndex
{
get
{
return _currentPlaylistIndex;
}
}
/// <summary>
/// Gets or sets the status file watcher.
/// </summary>
/// <value>The status file watcher.</value>
private FileSystemWatcher StatusFileWatcher { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has started playing.
/// </summary>
/// <value><c>true</c> if this instance has started playing; otherwise, <c>false</c>.</value>
private bool HasStartedPlaying { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has stopped playing.
/// </summary>
/// <value><c>true</c> if this instance has stopped playing; otherwise, <c>false</c>.</value>
private bool HasStoppedPlaying { get; set; }
/// <summary>
/// Determines whether this instance can play the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if this instance can play the specified item; otherwise, <c>false</c>.</returns>
public override bool CanPlay(BaseItemDto item)
{
return item.IsVideo || item.IsAudio;
}
/// <summary>
/// Called when [player stopped internal].
/// </summary>
protected override void OnPlayerStoppedInternal()
{
DisposeFileSystemWatcher();
HasStartedPlaying = false;
HasStoppedPlaying = false;
_currentPlaylistIndex = 0;
_currentPositionTicks = 0;
base.OnPlayerStoppedInternal();
}
/// <summary>
/// Gets the command arguments.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="options">The options.</param>
/// <param name="playerConfiguration">The player configuration.</param>
/// <returns>System.String.</returns>
protected override string GetCommandArguments(List<BaseItemDto> items, PlayOptions options, PlayerConfiguration playerConfiguration)
{
return "\"" + items[0].Path + "\"";
}
/// <summary>
/// Called when [external player launched].
/// </summary>
protected override void OnExternalPlayerLaunched()
{
base.OnExternalPlayerLaunched();
// If the playstate directory exists, start watching it
if (Directory.Exists(PlayStateDirectory))
{
ReloadFileSystemWatcher();
}
}
/// <summary>
/// Pauses the internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task PauseInternal()
{
return SendCommandToMMC("-pause");
}
/// <summary>
/// Uns the pause internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task UnPauseInternal()
{
return SendCommandToMMC("-play");
}
/// <summary>
/// Stops the internal.
/// </summary>
/// <returns>Task.</returns>
protected override Task StopInternal()
{
return SendCommandToMMC("-stop");
}
/// <summary>
/// Closes the player.
/// </summary>
/// <returns>Task.</returns>
protected Task ClosePlayer()
{
return SendCommandToMMC("-close");
}
/// <summary>
/// Seeks the internal.
/// </summary>
/// <param name="positionTicks">The position ticks.</param>
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">No media to seek to</exception>
protected override Task SeekInternal(long positionTicks)
{
if (CurrentMedia == null)
{
throw new InvalidOperationException("No media to seek to");
}
if (CurrentMedia.Chapters == null)
{
throw new InvalidOperationException("TMT5 cannot seek without chapter information");
}
var chapterIndex = 0;
for (var i = 0; i < CurrentMedia.Chapters.Count; i++)
{
if (CurrentMedia.Chapters[i].StartPositionTicks < positionTicks)
{
chapterIndex = i;
}
}
return JumpToChapter(chapterIndex);
}
/// <summary>
/// Jumps to chapter.
/// </summary>
/// <param name="chapter">The chapter.</param>
/// <returns>Task.</returns>
protected Task JumpToChapter(int chapter)
{
return SendCommandToMMC(" -chapter " + chapter);
}
/// <summary>
/// Sends an arbitrary command to the TMT MMC console
/// </summary>
/// <param name="command">The command.</param>
/// <returns>Task.</returns>
protected Task SendCommandToMMC(string command)
{
return Task.Run(() =>
{
var directory = Path.GetDirectoryName(CurrentPlayerConfiguration.Command);
var processInfo = new ProcessStartInfo
{
FileName = Path.Combine(directory, "MMCEDT5.exe"),
Arguments = command,
CreateNoWindow = true
};
Logger.Debug("{0} {1}", processInfo.FileName, processInfo.Arguments);
using (var process = Process.Start(processInfo))
{
process.WaitForExit(2000);
}
});
}
/// <summary>
/// Reloads the file system watcher.
/// </summary>
private void ReloadFileSystemWatcher()
{
DisposeFileSystemWatcher();
Logger.Info("Watching TMT folder: " + PlayStateDirectory);
StatusFileWatcher = new FileSystemWatcher(PlayStateDirectory, "*.set")
{
IncludeSubdirectories = true
};
// Need to include subdirectories since there are subfolders undearneath this with the TMT version #.
StatusFileWatcher.Changed += StatusFileWatcher_Changed;
StatusFileWatcher.EnableRaisingEvents = true;
}
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
/// Handles the Changed event of the StatusFileWatcher control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="FileSystemEventArgs" /> instance containing the event data.</param>
async void StatusFileWatcher_Changed(object sender, FileSystemEventArgs e)
{
Logger.Debug("TMT File Watcher reports change type {1} at {0}", e.FullPath, e.ChangeType);
NameValueCollection values;
try
{
values = FileSystem.ParseIniFile(e.FullPath);
}
catch (IOException)
{
// This can happen if the file is being written to at the exact moment we're trying to access it
// Unfortunately we kind of have to just eat it
return;
}
var tmtPlayState = values["State"];
if (tmtPlayState.Equals("play", StringComparison.OrdinalIgnoreCase))
{
PlayState = PlayState.Playing;
// Playback just started
HasStartedPlaying = true;
if (CurrentPlayOptions.StartPositionTicks > 0)
{
SeekInternal(CurrentPlayOptions.StartPositionTicks);
}
}
else if (tmtPlayState.Equals("pause", StringComparison.OrdinalIgnoreCase))
{
PlayState = PlayState.Paused;
}
// If playback has previously started...
// First notify the Progress event handler
// Then check if playback has stopped
if (HasStartedPlaying)
{
TimeSpan currentPosition;
//TimeSpan.TryParse(values["TotalTime"], out currentDuration);
if (TimeSpan.TryParse(values["CurTime"], UsCulture, out currentPosition))
{
_currentPositionTicks = currentPosition.Ticks;
}
_currentPlaylistIndex = 0;
// Playback has stopped
if (tmtPlayState.Equals("stop", StringComparison.OrdinalIgnoreCase))
{
Logger.Info("Playstate changed to stopped");
if (!HasStoppedPlaying)
{
HasStoppedPlaying = true;
DisposeFileSystemWatcher();
await ClosePlayer().ConfigureAwait(false);
}
}
}
}
/// <summary>
/// Disposes the file system watcher.
/// </summary>
private void DisposeFileSystemWatcher()
{
if (StatusFileWatcher != null)
{
StatusFileWatcher.EnableRaisingEvents = false;
StatusFileWatcher.Changed -= StatusFileWatcher_Changed;
StatusFileWatcher.Dispose();
StatusFileWatcher = null;
}
}
/// <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 override void Dispose(bool dispose)
{
if (dispose)
{
DisposeFileSystemWatcher();
}
base.Dispose(dispose);
}
}
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -1,314 +0,0 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace MediaBrowser.Plugins.Trailers
{
/// <summary>
/// Fetches Apple's list of current movie trailers
/// </summary>
public static class AppleTrailerListingDownloader
{
/// <summary>
/// The trailer feed URL
/// </summary>
private const string TrailerFeedUrl = "http://trailers.apple.com/trailers/home/xml/current_720p.xml";
/// <summary>
/// Downloads a list of trailer info's from the apple url
/// </summary>
/// <returns>Task{List{TrailerInfo}}.</returns>
public static async Task<List<TrailerInfo>> GetTrailerList(CancellationToken cancellationToken)
{
var stream = await Kernel.Instance.HttpManager.Get(TrailerFeedUrl, Kernel.Instance.ResourcePools.AppleTrailerVideos, cancellationToken).ConfigureAwait(false);
var list = new List<TrailerInfo>();
using (var reader = XmlReader.Create(stream, new XmlReaderSettings { Async = true }))
{
await reader.MoveToContentAsync().ConfigureAwait(false);
while (await reader.ReadAsync().ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "movieinfo":
var trailer = FetchTrailerInfo(reader.ReadSubtree());
list.Add(trailer);
break;
}
}
}
}
return list;
}
/// <summary>
/// Fetches trailer info from an xml node
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>TrailerInfo.</returns>
private static TrailerInfo FetchTrailerInfo(XmlReader reader)
{
var trailerInfo = new TrailerInfo { };
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "info":
FetchInfo(reader.ReadSubtree(), trailerInfo);
break;
case "cast":
FetchCast(reader.ReadSubtree(), trailerInfo);
break;
case "genre":
FetchGenres(reader.ReadSubtree(), trailerInfo);
break;
case "poster":
FetchPosterUrl(reader.ReadSubtree(), trailerInfo);
break;
case "preview":
FetchTrailerUrl(reader.ReadSubtree(), trailerInfo);
break;
default:
reader.Skip();
break;
}
}
}
return trailerInfo;
}
private static readonly CultureInfo USCulture = new CultureInfo("en-US");
/// <summary>
/// Fetches from the info node
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="info">The info.</param>
private static void FetchInfo(XmlReader reader, TrailerInfo info)
{
reader.MoveToContent();
reader.Read();
while (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "title":
info.Video.Name = reader.ReadStringSafe();
break;
case "runtime":
{
var runtime = reader.ReadStringSafe();
if (!string.IsNullOrWhiteSpace(runtime))
{
if (runtime.StartsWith(":", StringComparison.OrdinalIgnoreCase))
{
runtime = "0" + runtime;
}
TimeSpan runtimeTimeSpan;
if (TimeSpan.TryParse(runtime, USCulture, out runtimeTimeSpan))
{
info.Video.RunTimeTicks = runtimeTimeSpan.Ticks;
}
}
break;
}
case "rating":
info.Video.OfficialRating = reader.ReadStringSafe();
break;
case "studio":
{
var studio = reader.ReadStringSafe();
if (!string.IsNullOrWhiteSpace(studio))
{
info.Video.AddStudio(studio);
}
break;
}
case "postdate":
{
DateTime date;
if (DateTime.TryParse(reader.ReadStringSafe(), USCulture, DateTimeStyles.None, out date))
{
info.PostDate = date;
}
break;
}
case "releasedate":
{
var val = reader.ReadStringSafe();
if (!string.IsNullOrWhiteSpace(val))
{
DateTime date;
if (DateTime.TryParse(val, USCulture, DateTimeStyles.None, out date))
{
info.Video.PremiereDate = date;
info.Video.ProductionYear = date.Year;
}
}
break;
}
case "director":
{
var directors = reader.ReadStringSafe() ?? string.Empty;
foreach (var director in directors.Split(',', StringSplitOptions.RemoveEmptyEntries))
{
var name = director.Trim();
if (!string.IsNullOrWhiteSpace(name))
{
info.Video.AddPerson(new PersonInfo { Name = name, Type = PersonType.Director });
}
}
break;
}
case "description":
info.Video.Overview = reader.ReadStringSafe();
break;
default:
reader.Skip();
break;
}
}
}
/// <summary>
/// Fetches from the genre node
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="info">The info.</param>
private static void FetchGenres(XmlReader reader, TrailerInfo info)
{
reader.MoveToContent();
reader.Read();
while (reader.IsStartElement())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "name":
info.Video.AddGenre(reader.ReadStringSafe());
break;
default:
reader.Skip();
break;
}
}
}
}
/// <summary>
/// Fetches from the cast node
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="info">The info.</param>
private static void FetchCast(XmlReader reader, TrailerInfo info)
{
reader.MoveToContent();
reader.Read();
while (reader.IsStartElement())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "name":
info.Video.AddPerson(new PersonInfo { Name = reader.ReadStringSafe(), Type = PersonType.Actor });
break;
default:
reader.Skip();
break;
}
}
}
}
/// <summary>
/// Fetches from the preview node
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="info">The info.</param>
private static void FetchTrailerUrl(XmlReader reader, TrailerInfo info)
{
reader.MoveToContent();
reader.Read();
while (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "large":
info.TrailerUrl = reader.ReadStringSafe();
break;
default:
reader.Skip();
break;
}
}
}
/// <summary>
/// Fetches from the poster node
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="info">The info.</param>
private static void FetchPosterUrl(XmlReader reader, TrailerInfo info)
{
reader.MoveToContent();
reader.Read();
while (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "location":
info.ImageUrl = reader.ReadStringSafe();
break;
case "xlarge":
info.HdImageUrl = reader.ReadStringSafe();
break;
default:
reader.Skip();
break;
}
}
}
}
}

View File

@ -1,46 +0,0 @@
using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Plugins.Trailers.Configuration
{
/// <summary>
/// Class PluginConfiguration
/// </summary>
public class PluginConfiguration : BasePluginConfiguration
{
/// <summary>
/// Gets or sets the name of the folder.
/// </summary>
/// <value>The name of the folder.</value>
public string FolderName { get; set; }
/// <summary>
/// Trailers older than this will not be downloaded and deleted if already downloaded.
/// </summary>
/// <value>The max trailer age.</value>
public int? MaxTrailerAge { get; set; }
/// <summary>
/// Gets the path to where trailers should be downloaded.
/// If not supplied then programdata/cache/trailers will be used.
/// </summary>
/// <value>The download path.</value>
public string DownloadPath { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [delete old trailers].
/// </summary>
/// <value><c>true</c> if [delete old trailers]; otherwise, <c>false</c>.</value>
public bool DeleteOldTrailers { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="PluginConfiguration" /> class.
/// </summary>
public PluginConfiguration()
: base()
{
FolderName = "Trailers";
MaxTrailerAge = 60;
}
}
}

View File

@ -1,50 +0,0 @@
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller.Plugins;
using System.ComponentModel.Composition;
using System.IO;
namespace MediaBrowser.Plugins.Trailers.Configuration
{
/// <summary>
/// Class TrailerConfigurationPage
/// </summary>
[Export(typeof(BaseConfigurationPage))]
class TrailerConfigurationPage : BaseConfigurationPage
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "Trailers"; }
}
/// <summary>
/// Gets the HTML stream.
/// </summary>
/// <returns>Stream.</returns>
public override Stream GetHtmlStream()
{
return GetHtmlStreamFromManifestResource("MediaBrowser.Plugins.Trailers.Configuration.configPage.html");
}
/// <summary>
/// Gets the owner plugin.
/// </summary>
/// <returns>BasePlugin.</returns>
public override IPlugin GetOwnerPlugin()
{
return Plugin.Instance;
}
/// <summary>
/// Gets the type of the configuration page.
/// </summary>
/// <value>The type of the configuration page.</value>
public override ConfigurationPageType ConfigurationPageType
{
get { return ConfigurationPageType.PluginConfiguration; }
}
}
}

View File

@ -1,119 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Trailers</title>
</head>
<body>
<div id="trailersConfigurationPage" data-role="page" class="page type-interior pluginConfigurationPage">
<div data-role="content">
<div class="content-primary">
<form id="trailersConfigurationForm">
<ul class="ulForm" data-role="listview">
<li>
<label for="txtFolderName">
Trailer collection name:
</label>
<input id="txtFolderName" name="txtFolderName" />
</li>
<li>
<label for="txtMaxTrailerAge">
Max trailer age (days):
</label>
<input type="number" id="txtMaxTrailerAge" name="txtMaxTrailerAge" pattern="[0-9]*" min="1" />
<div class="fieldDescription">
If specified, trailers older than this will not be downloaded
</div>
</li>
<li>
<input type="checkbox" id="chkDeleteOldTrailers" name="chkDeleteOldTrailers" />
<label for="chkDeleteOldTrailers">Delete trailers older than the max age</label>
</li>
<li>
<label for="txtDownloadPath">
Download path:
</label>
<div style="display: inline-block; width:92%;">
<input id="txtDownloadPath" name="txtDownloadPath" data-inline="true" />
</div>
<button type="button" data-icon="folder-close" data-iconpos="notext" data-inline="true" onclick="TrailersConfigurationPage.selectDirectory();">Select Directory</button>
<div class="fieldDescription">
By default, trailers are downloaded to an internal data directory. Using a different location may make it easier to share over your network.
</div>
</li>
<li>
<button type="submit" data-theme="b">Save</button>
<button type="button" onclick="history.back();">Cancel</button>
</li>
</ul>
</form>
</div>
</div>
<script type="text/javascript">
var TrailersConfigurationPage = {
pluginUniqueId: "986a7283-205a-4436-862d-23135c067f8a",
selectDirectory: function () {
Dashboard.selectDirectory({
callback: function (path) {
if (path) {
$('#txtDownloadPath', $.mobile.activePage).val(path);
}
$('#popupDirectoryPicker', $.mobile.activePage).popup("close");
},
header: "Select Trailer Path"
});
}
};
$('#trailersConfigurationPage').on('pageshow', function (event) {
Dashboard.showLoadingMsg();
var page = this;
ApiClient.getPluginConfiguration(TrailersConfigurationPage.pluginUniqueId).done(function (config) {
$('#txtDownloadPath', page).val(config.DownloadPath);
$('#txtFolderName', page).val(config.FolderName);
$('#txtMaxTrailerAge', page).val(config.MaxTrailerAge || "");
$('#chkDeleteOldTrailers', page).checked(config.DeleteOldTrailers).checkboxradio("refresh");
Dashboard.hideLoadingMsg();
});
});
$('#trailersConfigurationForm').on('submit', function (e) {
Dashboard.showLoadingMsg();
var form = this;
ApiClient.getPluginConfiguration(TrailersConfigurationPage.pluginUniqueId).done(function (config) {
config.DownloadPath = $('#txtDownloadPath', form).val();
config.FolderName = $('#txtFolderName', form).val();
var maxTrailerAge = $('#txtMaxTrailerAge', form).val();
config.MaxTrailerAge = maxTrailerAge ? maxTrailerAge : null;
config.DeleteOldTrailers = $('#chkDeleteOldTrailers', form).checked();
ApiClient.updatePluginConfiguration(TrailersConfigurationPage.pluginUniqueId, config).done(Dashboard.processPluginConfigurationUpdateResult);
});
// Disable default form submission
return false;
});
</script>
</div>
</body>
</html>

View File

@ -1,33 +0,0 @@
using MediaBrowser.Controller.Entities;
using System.ComponentModel.Composition;
namespace MediaBrowser.Plugins.Trailers.Entities
{
/// <summary>
/// Class TrailerCollectionFolder
/// </summary>
[Export(typeof(BasePluginFolder))]
class TrailerCollectionFolder : BasePluginFolder
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
{
get
{
return Plugin.Instance.Configuration.FolderName;
}
}
/// <summary>
/// Gets the path.
/// </summary>
/// <value>The path.</value>
public override string Path
{
get { return Plugin.Instance.DownloadPath; }
}
}
}

View File

@ -1,88 +0,0 @@
<?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>{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Plugins.Trailers</RootNamespace>
<AssemblyName>MediaBrowser.Plugins.Trailers</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>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<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="AppleTrailerListingDownloader.cs" />
<Compile Include="Configuration\PluginConfiguration.cs" />
<Compile Include="Configuration\TrailerConfigurationPage.cs" />
<Compile Include="Providers\TrailerFromJsonProvider.cs" />
<Compile Include="Resolvers\TrailerResolver.cs" />
<Compile Include="ScheduledTasks\CurrentTrailerDownloadTask.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Entities\TrailerCollectionFolder.cs" />
<Compile Include="TrailerInfo.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>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Configuration\configPage.html" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData-Server\Plugins\" /y</PostBuildEvent>
</PropertyGroup>
<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>

View File

@ -1,119 +0,0 @@
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller.ScheduledTasks;
using MediaBrowser.Model.Plugins;
using MediaBrowser.Plugins.Trailers.Configuration;
using MediaBrowser.Plugins.Trailers.ScheduledTasks;
using System;
using System.ComponentModel.Composition;
using System.IO;
namespace MediaBrowser.Plugins.Trailers
{
/// <summary>
/// Class Plugin
/// </summary>
[Export(typeof(IPlugin))]
public class Plugin : BasePlugin<PluginConfiguration>
{
/// <summary>
/// Gets the name of the plugin
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "Trailers"; }
}
/// <summary>
/// Gets the description.
/// </summary>
/// <value>The description.</value>
public override string Description
{
get
{
return "Movie trailers for your collection.";
}
}
/// <summary>
/// Gets the instance.
/// </summary>
/// <value>The instance.</value>
public static Plugin Instance { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="Plugin" /> class.
/// </summary>
public Plugin()
: base()
{
Instance = this;
}
/// <summary>
/// The _download path
/// </summary>
private string _downloadPath;
/// <summary>
/// Gets the path to the trailer download directory
/// </summary>
/// <value>The download path.</value>
public string DownloadPath
{
get
{
if (_downloadPath == null)
{
// Use
_downloadPath = Configuration.DownloadPath;
if (string.IsNullOrWhiteSpace(_downloadPath))
{
_downloadPath = Path.Combine(Controller.Kernel.Instance.ApplicationPaths.DataPath, Name);
}
if (!Directory.Exists(_downloadPath))
{
Directory.CreateDirectory(_downloadPath);
}
}
return _downloadPath;
}
}
/// <summary>
/// Starts the plugin on the server
/// </summary>
/// <param name="isFirstRun">if set to <c>true</c> [is first run].</param>
protected override void InitializeOnServer(bool isFirstRun)
{
base.InitializeOnServer(isFirstRun);
if (isFirstRun)
{
Kernel.TaskManager.QueueScheduledTask<CurrentTrailerDownloadTask>();
}
}
/// <summary>
/// Completely overwrites the current configuration with a new copy
/// Returns true or false indicating success or failure
/// </summary>
/// <param name="configuration">The configuration.</param>
public override void UpdateConfiguration(BasePluginConfiguration configuration)
{
var config = (PluginConfiguration) configuration;
var pathChanged = !string.Equals(Configuration.DownloadPath, config.DownloadPath, StringComparison.OrdinalIgnoreCase);
base.UpdateConfiguration(configuration);
if (pathChanged)
{
_downloadPath = null;
Kernel.TaskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
}
}
}
}

View File

@ -1,34 +0,0 @@
using System.Reflection;
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.Plugins.Trailers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.Plugins.Trailers")]
[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("986a7283-205a-4436-862d-23135c067f8a")]
// 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.*")]

View File

@ -1,143 +0,0 @@
using MediaBrowser.Common.Serialization;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Plugins.Trailers.Entities;
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Plugins.Trailers.Providers
{
/// <summary>
/// Class TrailerFromJsonProvider
/// </summary>
[Export(typeof(BaseMetadataProvider))]
class TrailerFromJsonProvider : BaseMetadataProvider
{
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public override bool Supports(BaseItem item)
{
var trailer = item as Trailer;
return trailer != null && trailer.Parent is TrailerCollectionFolder;
}
/// <summary>
/// Override this to return the date that should be compared to the last refresh date
/// to determine if this provider should be re-fetched.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>DateTime.</returns>
protected override DateTime CompareDate(BaseItem item)
{
var entry = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "trailer.json"));
return entry != null ? entry.Value.LastWriteTimeUtc : DateTime.MinValue;
}
/// <summary>
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
/// </summary>
/// <param name="item">The item.</param>
/// <param name="force">if set to <c>true</c> [force].</param>
/// <returns>Task{System.Boolean}.</returns>
protected override Task<bool> FetchAsyncInternal(BaseItem item, bool force, CancellationToken cancellationToken)
{
return Task.Run(() => Fetch((Trailer)item));
}
/// <summary>
/// Fetches the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool Fetch(Trailer item)
{
var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, "trailer.json"));
if (metadataFile.HasValue)
{
var tempTrailer = JsonSerializer.DeserializeFromFile<Trailer>(metadataFile.Value.Path);
ImportMetdata(tempTrailer, item);
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
return false;
}
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>The priority.</value>
public override MetadataProviderPriority Priority
{
get { return MetadataProviderPriority.First; }
}
/// <summary>
/// Imports the metdata.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="target">The target.</param>
private void ImportMetdata(Trailer source, Trailer target)
{
if (!string.IsNullOrWhiteSpace(source.Name))
{
target.Name = source.Name;
}
if (source.RunTimeTicks.HasValue)
{
target.RunTimeTicks = source.RunTimeTicks;
}
if (source.Genres != null)
{
foreach (var entry in source.Genres)
{
target.AddGenre(entry);
}
}
if (!string.IsNullOrWhiteSpace(source.OfficialRating))
{
target.OfficialRating = source.OfficialRating;
}
if (!string.IsNullOrWhiteSpace(source.Overview))
{
target.Overview = source.Overview;
}
if (source.People != null)
{
target.AddPeople(source.People);
}
if (source.PremiereDate.HasValue)
{
target.PremiereDate = source.PremiereDate;
}
if (source.ProductionYear.HasValue)
{
target.ProductionYear = source.ProductionYear;
}
if (source.Studios != null)
{
foreach (var entry in source.Studios)
{
target.AddStudio(entry);
}
}
}
}
}

View File

@ -1,51 +0,0 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
using System;
using System.ComponentModel.Composition;
using System.Linq;
namespace MediaBrowser.Plugins.Trailers.Resolvers
{
/// <summary>
/// Class TrailerResolver
/// </summary>
[Export(typeof(IBaseItemResolver))]
public class TrailerResolver : BaseVideoResolver<Trailer>
{
/// <summary>
/// Resolves the specified args.
/// </summary>
/// <param name="args">The args.</param>
/// <returns>Trailer.</returns>
protected override Trailer Resolve(ItemResolveArgs args)
{
// Must be a directory and under the trailer download folder
if (args.IsDirectory && args.Path.StartsWith(Plugin.Instance.DownloadPath, StringComparison.OrdinalIgnoreCase))
{
// The trailer must be a video file
return FindTrailer(args);
}
return null;
}
/// <summary>
/// Finds a movie based on a child file system entries
/// </summary>
/// <param name="args">The args.</param>
/// <returns>Trailer.</returns>
private Trailer FindTrailer(ItemResolveArgs args)
{
// Loop through each child file/folder and see if we find a video
return args.FileSystemChildren
.Where(c => !c.IsDirectory)
.Select(child => base.Resolve(new ItemResolveArgs
{
FileInfo = child,
Path = child.Path
}))
.FirstOrDefault(i => i != null);
}
}
}

View File

@ -1,311 +0,0 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Common.Serialization;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Plugins.Trailers.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Plugins.Trailers.ScheduledTasks
{
/// <summary>
/// Downloads trailers from the web at scheduled times
/// </summary>
[Export(typeof(IScheduledTask))]
public class CurrentTrailerDownloadTask : BaseScheduledTask<Kernel>
{
/// <summary>
/// Creates the triggers that define when the task will run
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
protected override IEnumerable<BaseTaskTrigger> 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 async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
{
// Get the list of trailers
var trailers = await AppleTrailerListingDownloader.GetTrailerList(cancellationToken).ConfigureAwait(false);
progress.Report(1);
var trailersToDownload = trailers.Where(t => !IsOldTrailer(t.Video)).ToList();
cancellationToken.ThrowIfCancellationRequested();
var numComplete = 0;
// Fetch them all in parallel
var tasks = trailersToDownload.Select(t => Task.Run(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
try
{
await DownloadTrailer(t, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error downloading {0}", ex, t.TrailerUrl);
}
// Update progress
lock (progress)
{
numComplete++;
double percent = numComplete;
percent /= trailersToDownload.Count;
// Leave 1% for DeleteOldTrailers
progress.Report((99 * percent) + 1);
}
}));
cancellationToken.ThrowIfCancellationRequested();
await Task.WhenAll(tasks).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
if (Plugin.Instance.Configuration.DeleteOldTrailers)
{
// Enforce MaxTrailerAge
DeleteOldTrailers();
}
progress.Report(100);
}
/// <summary>
/// Downloads a single trailer into the trailers directory
/// </summary>
/// <param name="trailer">The trailer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
private async Task DownloadTrailer(TrailerInfo trailer, CancellationToken cancellationToken)
{
// Construct the trailer foldername
var folderName = FileSystem.GetValidFilename(trailer.Video.Name);
if (trailer.Video.ProductionYear.HasValue)
{
folderName += string.Format(" ({0})", trailer.Video.ProductionYear);
}
var folderPath = Path.Combine(Plugin.Instance.DownloadPath, folderName);
// Figure out which image we're going to download
var imageUrl = trailer.HdImageUrl ?? trailer.ImageUrl;
// Construct the video filename (to match the folder name)
var videoFileName = Path.ChangeExtension(folderName, Path.GetExtension(trailer.TrailerUrl));
// Construct the image filename (folder + original extension)
var imageFileName = Path.ChangeExtension("folder", Path.GetExtension(imageUrl));
// Construct full paths
var videoFilePath = Path.Combine(folderPath, videoFileName);
var imageFilePath = Path.Combine(folderPath, imageFileName);
// Create tasks to download each of them, if we don't already have them
Task<string> videoTask = null;
Task<MemoryStream> imageTask = null;
var tasks = new List<Task>();
if (!File.Exists(videoFilePath))
{
Logger.Info("Downloading trailer: " + trailer.TrailerUrl);
// Fetch the video to a temp file because it's too big to put into a MemoryStream
videoTask = Kernel.HttpManager.FetchToTempFile(trailer.TrailerUrl, Kernel.ResourcePools.AppleTrailerVideos, cancellationToken, new Progress<double> { }, "QuickTime/7.6.2");
tasks.Add(videoTask);
}
if (!string.IsNullOrWhiteSpace(imageUrl) && !File.Exists(imageFilePath))
{
// Fetch the image to a memory stream
Logger.Info("Downloading trailer image: " + imageUrl);
imageTask = Kernel.HttpManager.FetchToMemoryStream(imageUrl, Kernel.ResourcePools.AppleTrailerImages, cancellationToken);
tasks.Add(imageTask);
}
try
{
// Wait for both downloads to finish
await Task.WhenAll(tasks).ConfigureAwait(false);
}
catch (HttpException ex)
{
Logger.ErrorException("Error downloading trailer file or image", ex);
}
var videoFailed = false;
var directoryEnsured = false;
// Proces the video file task result
if (videoTask != null)
{
if (videoTask.Status == TaskStatus.RanToCompletion)
{
EnsureDirectory(folderPath);
directoryEnsured = true;
// Move the temp file to the final destination
try
{
File.Move(videoTask.Result, videoFilePath);
}
catch (IOException ex)
{
Logger.ErrorException("Error moving temp file", ex);
File.Delete(videoTask.Result);
videoFailed = true;
}
}
else
{
Logger.Info("Trailer download failed: " + trailer.TrailerUrl);
// Don't bother with the image if the video download failed
videoFailed = true;
}
}
// Process the image file task result
if (imageTask != null && !videoFailed && imageTask.Status == TaskStatus.RanToCompletion)
{
if (!directoryEnsured)
{
EnsureDirectory(folderPath);
}
try
{
// Save the image to the file system
using (var fs = new FileStream(imageFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
using (var sourceStream = imageTask.Result)
{
await sourceStream.CopyToAsync(fs).ConfigureAwait(false);
}
}
}
catch (IOException ex)
{
Logger.ErrorException("Error saving image to file system", ex);
}
}
// Save metadata only if the video was downloaded
if (!videoFailed && videoTask != null)
{
JsonSerializer.SerializeToFile(trailer.Video, Path.Combine(folderPath, "trailer.json"));
}
}
/// <summary>
/// Determines whether [is old trailer] [the specified trailer].
/// </summary>
/// <param name="trailer">The trailer.</param>
/// <returns><c>true</c> if [is old trailer] [the specified trailer]; otherwise, <c>false</c>.</returns>
private bool IsOldTrailer(Trailer trailer)
{
if (!Plugin.Instance.Configuration.MaxTrailerAge.HasValue)
{
return false;
}
if (!trailer.PremiereDate.HasValue)
{
return false;
}
var now = DateTime.UtcNow;
// Not old if it still hasn't premiered.
if (now < trailer.PremiereDate.Value)
{
return false;
}
return (DateTime.UtcNow - trailer.PremiereDate.Value).TotalDays >
Plugin.Instance.Configuration.MaxTrailerAge.Value;
}
/// <summary>
/// Deletes trailers that are older than the supplied date
/// </summary>
private void DeleteOldTrailers()
{
var collectionFolder = (Folder)Kernel.RootFolder.Children.First(c => c.GetType().Name.Equals(typeof(TrailerCollectionFolder).Name));
foreach (var trailer in collectionFolder.RecursiveChildren.OfType<Trailer>().Where(IsOldTrailer))
{
Logger.Info("Deleting old trailer: " + trailer.Name);
Directory.Delete(Path.GetDirectoryName(trailer.Path), true);
}
}
/// <summary>
/// Ensures the directory.
/// </summary>
/// <param name="path">The path.</param>
private void EnsureDirectory(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
/// <summary>
/// Gets the name of the task
/// </summary>
/// <value>The name.</value>
public override string Name
{
get { return "Find current trailers"; }
}
/// <summary>
/// Gets the category.
/// </summary>
/// <value>The category.</value>
public override string Category
{
get
{
return "Trailers";
}
}
/// <summary>
/// Gets the description.
/// </summary>
/// <value>The description.</value>
public override string Description
{
get { return "Searches the web for upcoming movie trailers, and downloads them based on your Trailer plugin settings."; }
}
}
}

View File

@ -1,45 +0,0 @@
using MediaBrowser.Controller.Entities;
using System;
namespace MediaBrowser.Plugins.Trailers
{
/// <summary>
/// This is a stub class used to hold information about a trailer
/// </summary>
public class TrailerInfo
{
/// <summary>
/// Gets or sets the video.
/// </summary>
/// <value>The video.</value>
public Trailer Video { get; set; }
/// <summary>
/// Gets or sets the image URL.
/// </summary>
/// <value>The image URL.</value>
public string ImageUrl { get; set; }
/// <summary>
/// Gets or sets the hd image URL.
/// </summary>
/// <value>The hd image URL.</value>
public string HdImageUrl { get; set; }
/// <summary>
/// Gets or sets the trailer URL.
/// </summary>
/// <value>The trailer URL.</value>
public string TrailerUrl { get; set; }
/// <summary>
/// Gets or sets the post date.
/// </summary>
/// <value>The post date.</value>
public DateTime PostDate { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="TrailerInfo" /> class.
/// </summary>
public TrailerInfo()
{
Video = new Trailer();
}
}
}

View File

@ -11,10 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.DefaultTheme", "MediaBrowser.Plugins.DefaultTheme\MediaBrowser.Plugins.DefaultTheme.csproj", "{6E892999-711D-4E24-8BAC-DACF5BFA783A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.MpcHc", "MediaBrowser.Plugins.MpcHc\MediaBrowser.Plugins.MpcHc.csproj", "{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.Tmt5", "MediaBrowser.Plugins.Tmt5\MediaBrowser.Plugins.Tmt5.csproj", "{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.UI.Uninstall", "MediaBrowser.UI.Uninstall\MediaBrowser.UI.Uninstall.csproj", "{E4BE0659-4084-407B-B8A8-67802331CC9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.IsoMounter", "MediaBrowser.IsoMounter\MediaBrowser.IsoMounter.csproj", "{5356AE30-6A6E-4A64-81E3-F76C50595E64}"
@ -95,26 +91,6 @@ Global
{6E892999-711D-4E24-8BAC-DACF5BFA783A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{6E892999-711D-4E24-8BAC-DACF5BFA783A}.Release|x86.ActiveCfg = Release|Any CPU
{6E892999-711D-4E24-8BAC-DACF5BFA783A}.Release|x86.Build.0 = Release|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Release|Any CPU.Build.0 = Release|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2E94BC08-A7A2-42DD-9893-EAA3DACD1CF9}.Release|x86.ActiveCfg = Release|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Debug|x86.ActiveCfg = Debug|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Release|Any CPU.Build.0 = Release|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BE9BAA85-9EF2-4308-92E4-0D2B6E33C487}.Release|x86.ActiveCfg = Release|Any CPU
{E4BE0659-4084-407B-B8A8-67802331CC9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4BE0659-4084-407B-B8A8-67802331CC9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4BE0659-4084-407B-B8A8-67802331CC9E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

View File

@ -217,7 +217,7 @@ namespace MediaBrowser.UI.Controller
_logger.Info("Downloading {0} Configuration", pluginInfo.Name);
// First download to a MemoryStream. This way if the download is cut off, we won't be left with a partial file
using (var stream = await UIKernel.Instance.ApiClient.GetPluginConfigurationFileAsync(pluginInfo.UniqueId).ConfigureAwait(false))
using (var stream = await UIKernel.Instance.ApiClient.GetPluginConfigurationFileAsync(pluginInfo.Id).ConfigureAwait(false))
{
using (var memoryStream = new MemoryStream())
{

View File

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B5ECE1FB-618E-420B-9A99-8E972D76920A}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.UI</RootNamespace>
<AssemblyName>MediaBrowser.UI</AssemblyName>
@ -57,7 +57,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>MediaBrowser.UI.App</StartupObject>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\Images\Icon.ico</ApplicationIcon>

View File

@ -25,7 +25,7 @@ namespace MediaBrowser.WebDashboard.Api
/// Class GetDashboardConfigurationPages
/// </summary>
[Route("/dashboard/ConfigurationPages", "GET")]
public class GetDashboardConfigurationPages : IReturn<List<BaseConfigurationPage>>
public class GetDashboardConfigurationPages : IReturn<List<IPluginConfigurationPage>>
{
/// <summary>
/// Gets or sets the type of the page.
@ -38,7 +38,7 @@ namespace MediaBrowser.WebDashboard.Api
/// Class GetDashboardConfigurationPage
/// </summary>
[Route("/dashboard/ConfigurationPage", "GET")]
public class GetDashboardConfigurationPage : IReturn<BaseConfigurationPage>
public class GetDashboardConfigurationPage : IReturn<IPluginConfigurationPage>
{
/// <summary>
/// Gets or sets the name.
@ -139,9 +139,8 @@ namespace MediaBrowser.WebDashboard.Api
var kernel = (Kernel)Kernel;
var page = kernel.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
var plugin = page.GetOwnerPlugin();
return ToStaticResult(plugin.Version.ToString().GetMD5(), plugin.AssemblyDateLastModified, null, MimeTypes.GetMimeType("page.html"), () => ModifyHtml(page.GetHtmlStream()));
return ToStaticResult(page.Version.GetMD5(), page.DateLastModified, null, MimeTypes.GetMimeType("page.html"), () => ModifyHtml(page.GetHtmlStream()));
}
/// <summary>

View File

@ -41,7 +41,7 @@
var options = PluginUpdatesPage.getHtmlOptions(["Off", "On"], (plugin.EnableAutoUpdate ? "On" : "Off"));
html += "<td>";
html += "<select data-uniqueid='" + plugin.UniqueId + "' onchange='PluginUpdatesPage.setAutoUpdate(this);' data-role='slider' id='" + fieldId + "' name='" + fieldId + "'>" + options + "</select>";
html += "<select data-id='" + plugin.Id + "' onchange='PluginUpdatesPage.setAutoUpdate(this);' data-role='slider' id='" + fieldId + "' name='" + fieldId + "'>" + options + "</select>";
html += "</td>";
fieldId = "liPluginUpdateFieldb" + fieldIndex;
@ -49,7 +49,7 @@
options = PluginUpdatesPage.getHtmlOptions(["Release", "Beta", "Dev"], plugin.UpdateClass);
html += "<td>";
html += "<select data-uniqueid='" + plugin.UniqueId + "' onchange='PluginUpdatesPage.setUpdateClass(this);' data-inline='true' id='" + fieldId + "' name='" + fieldId + "'>" + options + "</select>";
html += "<select data-id='" + plugin.Id + "' onchange='PluginUpdatesPage.setUpdateClass(this);' data-inline='true' id='" + fieldId + "' name='" + fieldId + "'>" + options + "</select>";
html += "</td>";
html += "</tr>";
@ -79,7 +79,7 @@
setAutoUpdate: function (select) {
var id = $(select).attr('data-uniqueid');
var id = $(select).attr('data-id');
Dashboard.showLoadingMsg();
@ -93,7 +93,7 @@
setUpdateClass: function (select) {
var id = $(select).attr('data-uniqueid');
var id = $(select).attr('data-id');
Dashboard.showLoadingMsg();

View File

@ -40,7 +40,7 @@
}
var configPage = $.grep(pluginConfigurationPages, function (pluginConfigurationPage) {
return pluginConfigurationPage.OwnerPluginName == plugin.Name;
return pluginConfigurationPage.PluginId == plugin.Id;
})[0];
html += "<li>";
@ -56,7 +56,7 @@
html += "</a>";
if (!plugin.IsCorePlugin) {
html += "<a data-uniqueid='" + plugin.UniqueId + "' data-pluginname='" + plugin.Name + "' onclick='PluginsPage.deletePlugin(this);' href='#'>Delete</a>";
html += "<a data-id='" + plugin.Id + "' data-pluginname='" + plugin.Name + "' onclick='PluginsPage.deletePlugin(this);' href='#'>Delete</a>";
}
html += "</li>";
@ -70,7 +70,7 @@
deletePlugin: function (link) {
var name = link.getAttribute('data-pluginname');
var uniqueid = link.getAttribute('data-uniqueid');
var uniqueid = link.getAttribute('data-id');
var msg = "Are you sure you wish to uninstall " + name + "?";

View File

@ -20,8 +20,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Performance19.psess = Performance19.psess
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.Trailers", "MediaBrowser.Plugins.Trailers\MediaBrowser.Plugins.Trailers.csproj", "{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction.Javascript", "MediaBrowser.ApiInteraction.Javascript\MediaBrowser.ApiInteraction.Javascript.csproj", "{767B536E-D90C-4D74-A14B-8564B16F3499}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ApiInteraction", "MediaBrowser.ApiInteraction\MediaBrowser.ApiInteraction.csproj", "{921C0F64-FDA7-4E9F-9E73-0CB0EEDB2422}"
@ -41,8 +39,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDInfo", "BDInfo\BDInfo.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.IsoMounter", "MediaBrowser.IsoMounter\MediaBrowser.IsoMounter.csproj", "{5356AE30-6A6E-4A64-81E3-F76C50595E64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Plugins.Dlna", "MediaBrowser.Plugins.Dlna\MediaBrowser.Plugins.Dlna.csproj", "{A2CF4266-2110-419E-8620-E2FEEFCA0F48}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Installer", "MediaBrowser.Installer\MediaBrowser.Installer.csproj", "{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Sqlite", "MediaBrowser.Server.Sqlite\MediaBrowser.Server.Sqlite.csproj", "{8649ED6B-8504-4D00-BFA5-B8C73CC744DB}"
@ -163,21 +159,6 @@ Global
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x64.ActiveCfg = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU
{5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|x64.ActiveCfg = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|x86.ActiveCfg = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Debug|x86.Build.0 = Debug|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|Any CPU.Build.0 = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|Win32.ActiveCfg = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|x64.ActiveCfg = Release|Any CPU
{2F4C01E2-7C9F-4F08-922E-27AC4A1D53FF}.Release|x86.ActiveCfg = Release|Any CPU
{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Any CPU.Build.0 = Debug|Any CPU
{767B536E-D90C-4D74-A14B-8564B16F3499}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -267,20 +248,6 @@ Global
{5356AE30-6A6E-4A64-81E3-F76C50595E64}.Release|Win32.ActiveCfg = Release|Any CPU
{5356AE30-6A6E-4A64-81E3-F76C50595E64}.Release|x64.ActiveCfg = Release|Any CPU
{5356AE30-6A6E-4A64-81E3-F76C50595E64}.Release|x86.ActiveCfg = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|Win32.ActiveCfg = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|x64.ActiveCfg = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Debug|x86.ActiveCfg = Debug|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|Any CPU.Build.0 = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|Win32.ActiveCfg = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|x64.ActiveCfg = Release|Any CPU
{A2CF4266-2110-419E-8620-E2FEEFCA0F48}.Release|x86.ActiveCfg = Release|Any CPU
{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3879F78A-D6F6-45E5-B2A8-D8DCF2DABB74}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

View File

@ -0,0 +1 @@
da3d30d634468465d8995ba6cb1c0872959b3e9c