mirror of https://github.com/jellyfin/jellyfin.git
moved Plugins to separate repo
This commit is contained in:
parent
868a7ce9c8
commit
746c5d2fa7
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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
|
@ -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.*")]
|
|
@ -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>
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.*")]
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.*")]
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.*")]
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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."; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 + "?";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
da3d30d634468465d8995ba6cb1c0872959b3e9c
|
Loading…
Reference in New Issue