Add upnp configuration

This commit is contained in:
Luke Pulverenti 2014-02-25 23:38:21 -05:00
parent 7767580a3b
commit 13563b6047
21 changed files with 383 additions and 158 deletions

View File

@ -306,6 +306,26 @@ namespace MediaBrowser.Api
var auth = AuthorizationRequestFilterAttribute.GetAuthorization(Request);
// Login in the old way if the header is missing
if (string.IsNullOrEmpty(auth.Client) ||
string.IsNullOrEmpty(auth.Device) ||
string.IsNullOrEmpty(auth.DeviceId) ||
string.IsNullOrEmpty(auth.Version))
{
var success = await _userManager.AuthenticateUser(user, request.Password).ConfigureAwait(false);
if (!success)
{
// Unauthorized
throw new UnauthorizedAccessException("Invalid user or password entered.");
}
return new AuthenticationResult
{
User = _dtoService.GetUserDto(user)
};
}
var session = await _sessionMananger.AuthenticateNewSession(user, request.Password, auth.Client, auth.Version,
auth.DeviceId, auth.Device, Request.RemoteIp).ConfigureAwait(false);

View File

@ -114,7 +114,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate);
request.CachePolicy = options.CachePolicy == Net.HttpRequestCachePolicy.None ?
new RequestCachePolicy(RequestCacheLevel.BypassCache) :
new RequestCachePolicy(RequestCacheLevel.Revalidate);
request.ConnectionGroupName = GetHostFromUrl(options.Url);
request.KeepAlive = true;
request.Method = method;
@ -144,7 +148,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate);
request.CachePolicy = options.CachePolicy == Net.HttpRequestCachePolicy.None ?
new RequestCachePolicy(RequestCacheLevel.BypassCache) :
new RequestCachePolicy(RequestCacheLevel.Revalidate);
request.ConnectionGroupName = GetHostFromUrl(options.Url);
request.KeepAlive = true;
request.Method = method;

View File

@ -72,6 +72,8 @@ namespace MediaBrowser.Common.Net
public bool BufferContent { get; set; }
public HttpRequestCachePolicy CachePolicy { get; set; }
private string GetHeaderValue(string name)
{
string value;
@ -89,7 +91,15 @@ namespace MediaBrowser.Common.Net
EnableHttpCompression = true;
BufferContent = true;
CachePolicy = HttpRequestCachePolicy.None;
RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
public enum HttpRequestCachePolicy
{
None = 1,
Validate = 2
}
}

View File

@ -305,12 +305,6 @@ namespace MediaBrowser.Controller.Entities
return GetCachedChildren();
}
/// <summary>
/// Gets or sets the current validation cancellation token source.
/// </summary>
/// <value>The current validation cancellation token source.</value>
private CancellationTokenSource CurrentValidationCancellationTokenSource { get; set; }
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
{
return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions());
@ -331,48 +325,9 @@ namespace MediaBrowser.Controller.Entities
return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService);
}
private async Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
{
cancellationToken.ThrowIfCancellationRequested();
// Cancel the current validation, if any
if (CurrentValidationCancellationTokenSource != null)
{
CurrentValidationCancellationTokenSource.Cancel();
}
// Create an inner cancellation token. This can cancel all validations from this level on down,
// but nothing above this
var innerCancellationTokenSource = new CancellationTokenSource();
try
{
CurrentValidationCancellationTokenSource = innerCancellationTokenSource;
var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(innerCancellationTokenSource.Token, cancellationToken);
await ValidateChildrenInternal(progress, linkedCancellationTokenSource.Token, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
{
Logger.Info("ValidateChildren cancelled for " + Name);
// If the outer cancelletion token in the cause for the cancellation, throw it
if (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken)
{
throw;
}
}
finally
{
// Null out the token source
if (CurrentValidationCancellationTokenSource == innerCancellationTokenSource)
{
CurrentValidationCancellationTokenSource = null;
}
innerCancellationTokenSource.Dispose();
}
return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
}
private Dictionary<Guid, BaseItem> GetActualChildrenDictionary()
@ -384,7 +339,7 @@ namespace MediaBrowser.Controller.Entities
var id = child.Id;
if (dictionary.ContainsKey(id))
{
Logger.Error( "Found folder containing items with duplicate id. Path: {0}, Child Name: {1}",
Logger.Error("Found folder containing items with duplicate id. Path: {0}, Child Name: {1}",
Path ?? Name,
child.Path ?? child.Name);
}

View File

@ -0,0 +1,55 @@
<?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>{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MediaBrowser.Dlna</RootNamespace>
<AssemblyName>MediaBrowser.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>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,31 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MediaBrowser.Dlna")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MediaBrowser.Dlna")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[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("c319ebfa-fd9d-42e4-ae74-a40039a6a688")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//

View File

@ -27,6 +27,12 @@ namespace MediaBrowser.Model.Configuration
/// <value><c>true</c> if [enable HTTP level logging]; otherwise, <c>false</c>.</value>
public bool EnableHttpLevelLogging { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [enable u pn p].
/// </summary>
/// <value><c>true</c> if [enable u pn p]; otherwise, <c>false</c>.</value>
public bool EnableUPnP { get; set; }
/// <summary>
/// Gets or sets the HTTP server port number.
/// </summary>
@ -222,6 +228,8 @@ namespace MediaBrowser.Model.Configuration
EnableAutomaticRestart = true;
EnablePeoplePrefixSubFolders = true;
EnableUPnP = true;
MinResumePct = 5;
MaxResumePct = 90;
MinResumeDurationSeconds = Convert.ToInt32(TimeSpan.FromMinutes(5).TotalSeconds);

View File

@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Mono", "MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj", "{175A9388-F352-4586-A6B4-070DED62B644}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@ -99,6 +101,14 @@ Global
{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|Any CPU.Build.0 = Release|Any CPU
{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU
{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.Build.0 = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x86.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x86.Build.0 = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release Mono|Any CPU.Build.0 = Release Mono|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.Build.0 = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj

View File

@ -182,6 +182,10 @@ namespace MediaBrowser.Providers.Manager
return result;
}
catch (OperationCanceledException)
{
return new List<RemoteImageInfo>();
}
catch (Exception ex)
{
_logger.ErrorException("{0} failed in GetImageInfos for type {1}", ex, provider.GetType().Name, item.GetType().Name);

View File

@ -35,9 +35,24 @@ namespace MediaBrowser.Providers.TV
public async Task Run(IEnumerable<IGrouping<string, Series>> series, CancellationToken cancellationToken)
{
foreach (var seriesGroup in series)
{
try
{
await Run(seriesGroup, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
break;
}
catch (DirectoryNotFoundException)
{
_logger.Warn("Series files missing for series id {0}", seriesGroup.Key);
}
catch (Exception ex)
{
_logger.ErrorException("Error in missing episode provider for series id {0}", ex, seriesGroup.Key);
}
}
}
private async Task Run(IGrouping<string, Series> group, CancellationToken cancellationToken)

View File

@ -0,0 +1,174 @@
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
using Mono.Nat;
using System;
using System.IO;
using System.Text;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
public class ExternalPortForwarding : IServerEntryPoint
{
private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
private bool _isStarted;
public ExternalPortForwarding(ILogger logger, IServerApplicationHost appHost, IServerConfigurationManager config)
{
_logger = logger;
_appHost = appHost;
_config = config;
_config.ConfigurationUpdated += _config_ConfigurationUpdated;
}
void _config_ConfigurationUpdated(object sender, EventArgs e)
{
var enable = _config.Configuration.EnableUPnP;
if (enable && !_isStarted)
{
Reload();
}
else if (!enable && _isStarted)
{
DisposeNat();
}
}
public void Run()
{
NatUtility.Logger = new LogWriter(_logger);
Reload();
}
private void Reload()
{
if (_config.Configuration.EnableUPnP)
{
_logger.Debug("Starting NAT discovery");
NatUtility.DeviceFound += NatUtility_DeviceFound;
NatUtility.DeviceLost += NatUtility_DeviceLost;
NatUtility.UnhandledException += NatUtility_UnhandledException;
NatUtility.StartDiscovery();
_isStarted = true;
}
}
void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
if (ex == null)
{
_logger.Error("Unidentified error reported by Mono.Nat");
}
else
{
// Seeing some blank exceptions coming through here
_logger.ErrorException("Error reported by Mono.Nat: ", ex);
}
}
void NatUtility_DeviceFound(object sender, DeviceEventArgs e)
{
try
{
var device = e.Device;
_logger.Debug("NAT device found: {0}", device.LocalAddress.ToString());
CreateRules(device);
}
catch (Exception ex)
{
_logger.ErrorException("Error creating port forwarding rules", ex);
}
}
private void CreateRules(INatDevice device)
{
var info = _appHost.GetSystemInfo();
CreatePortMap(device, info.HttpServerPortNumber);
if (info.WebSocketPortNumber != info.HttpServerPortNumber)
{
CreatePortMap(device, info.WebSocketPortNumber);
}
}
private void CreatePortMap(INatDevice device, int port)
{
_logger.Info("Creating port map on port {0}", port);
device.CreatePortMap(new Mapping(Protocol.Tcp, port, port)
{
Description = "Media Browser Server"
});
}
void NatUtility_DeviceLost(object sender, DeviceEventArgs e)
{
var device = e.Device;
_logger.Debug("NAT device lost: {0}", device.LocalAddress.ToString());
}
public void Dispose()
{
DisposeNat();
}
private void DisposeNat()
{
_logger.Debug("Stopping NAT discovery");
try
{
NatUtility.DeviceFound -= NatUtility_DeviceFound;
NatUtility.DeviceLost -= NatUtility_DeviceLost;
NatUtility.UnhandledException -= NatUtility_UnhandledException;
NatUtility.StopDiscovery();
}
catch (Exception ex)
{
_logger.ErrorException("Error stopping NAT Discovery", ex);
}
finally
{
_isStarted = false;
}
}
private class LogWriter : TextWriter
{
private readonly ILogger _logger;
public LogWriter(ILogger logger)
{
_logger = logger;
}
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
public override void WriteLine(string format, params object[] arg)
{
_logger.Debug(format, arg);
}
public override void WriteLine(string value)
{
_logger.Debug(value);
}
}
}
}

View File

@ -170,7 +170,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
File.Delete(file.FullName);
}
catch (IOException ex)
catch (Exception ex)
{
_logger.ErrorException("Error deleting file {0}", ex, file.FullName);
}

View File

@ -39,7 +39,16 @@ namespace MediaBrowser.Server.Implementations.IO
/// <summary>
/// Any file name ending in any of these will be ignored by the watchers
/// </summary>
private readonly IReadOnlyList<string> _alwaysIgnoreFiles = new List<string> { "thumbs.db", "small.jpg", "albumart.jpg" };
private readonly IReadOnlyList<string> _alwaysIgnoreFiles = new List<string>
{
"thumbs.db",
"small.jpg",
"albumart.jpg",
// WMC temp recording directories that will constantly be written to
"TempRec",
"TempSBE"
};
/// <summary>
/// The timer lock

View File

@ -56,6 +56,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll</HintPath>
</Reference>
<Reference Include="Mono.Nat">
<HintPath>..\packages\Mono.Nat.1.1.13\lib\Net40\Mono.Nat.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Api.Swagger">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
</Reference>
@ -112,6 +115,7 @@
<Compile Include="Drawing\UnplayedCountIndicator.cs" />
<Compile Include="Dto\DtoService.cs" />
<Compile Include="EntryPoints\AutomaticRestartEntryPoint.cs" />
<Compile Include="EntryPoints\ExternalPortForwarding.cs" />
<Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
<Compile Include="EntryPoints\LoadRegistrations.cs" />
<Compile Include="EntryPoints\Notifications\Notifier.cs" />

View File

@ -154,8 +154,6 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// </summary>
private void ReloadHttpServer(IEnumerable<string> urlPrefixes, bool enableHttpLogging)
{
DisposeHttpServer();
_logger.Info("Loading Http Server");
try

View File

@ -1,54 +0,0 @@
using Fleck;
using MediaBrowser.Common.Net;
using System;
using IWebSocketServer = MediaBrowser.Common.Net.IWebSocketServer;
namespace MediaBrowser.Server.Implementations.WebSocket
{
public class FleckServer : IWebSocketServer
{
private WebSocketServer _server;
public void Start(int portNumber)
{
var server = new WebSocketServer("ws://localhost:" + portNumber);
server.Start(socket =>
{
socket.OnOpen = () => OnClientConnected(socket);
});
_server = server;
}
public void Stop()
{
_server.Dispose();
}
private void OnClientConnected(Fleck.IWebSocketConnection context)
{
if (WebSocketConnected != null)
{
var socket = new FleckWebSocket(context);
WebSocketConnected(this, new WebSocketConnectEventArgs
{
WebSocket = socket,
Endpoint = context.ConnectionInfo.ClientIpAddress + ":" + context.ConnectionInfo.ClientPort
});
}
}
public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
public int Port
{
get { return _server.Port; }
}
public void Dispose()
{
_server.Dispose();
}
}
}

View File

@ -1,47 +0,0 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Net;
using System;
using System.Threading;
using System.Threading.Tasks;
using IWebSocketConnection = Fleck.IWebSocketConnection;
namespace MediaBrowser.Server.Implementations.WebSocket
{
public class FleckWebSocket : IWebSocket
{
private readonly IWebSocketConnection _connection;
public FleckWebSocket(IWebSocketConnection connection)
{
_connection = connection;
_connection.OnMessage = OnReceiveData;
}
public WebSocketState State
{
get { return _connection.IsAvailable ? WebSocketState.Open : WebSocketState.Closed; }
}
private void OnReceiveData(string data)
{
if (OnReceive != null)
{
OnReceive(data);
}
}
public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken)
{
return Task.Run(() => _connection.Send(bytes));
}
public void Dispose()
{
_connection.Close();
}
public Action<byte[]> OnReceiveBytes { get; set; }
public Action<string> OnReceive { get; set; }
}
}

View File

@ -2,6 +2,7 @@
<packages>
<package id="Alchemy" version="2.2.1" targetFramework="net45" />
<package id="MediaBrowser.BdInfo" version="1.0.0.10" targetFramework="net45" />
<package id="Mono.Nat" version="1.1.13" targetFramework="net45" />
<package id="morelinq" version="1.0.16006" targetFramework="net45" />
<package id="System.Data.SQLite.x86" version="1.0.90.0" targetFramework="net45" />
</packages>

View File

@ -100,6 +100,10 @@
<Project>{442B5058-DCAF-4263-BB6A-F21E31120A1B}</Project>
<Name>MediaBrowser.Providers</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Dlna\MediaBrowser.Dlna.csproj">
<Project>{734098eb-6dc1-4dd0-a1ca-3140dcd2737c}</Project>
<Name>MediaBrowser.Dlna</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</Project>
<Name>MediaBrowser.Model</Name>

View File

@ -191,6 +191,10 @@
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Dlna\MediaBrowser.Dlna.csproj">
<Project>{734098eb-6dc1-4dd0-a1ca-3140dcd2737c}</Project>
<Name>MediaBrowser.Dlna</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>

View File

@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model.Portable
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ServerApplication", "MediaBrowser.ServerApplication\MediaBrowser.ServerApplication.csproj", "{94ADE4D3-B7EC-45CD-A200-CC469433072B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Dlna", "MediaBrowser.Dlna\MediaBrowser.Dlna.csproj", "{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -231,6 +233,20 @@ Global
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|Win32.ActiveCfg = Release|Any CPU
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x64.ActiveCfg = Release|Any CPU
{94ADE4D3-B7EC-45CD-A200-CC469433072B}.Release|x86.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|Win32.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x64.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Debug|x86.ActiveCfg = Debug|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Any CPU.Build.0 = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|Win32.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x64.ActiveCfg = Release|Any CPU
{734098EB-6DC1-4DD0-A1CA-3140DCD2737C}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE