1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-14 11:23:42 +02:00

New: MediaCover api now includes several resized variants to save bandwidth for mobile apps.

banner-35.jpg (height)
banner-70.jpg
fanart-180.jpg (height)
fanart-360.jpg
poster-170.jpg (width)
poster-340.jpg
This commit is contained in:
Taloth Saldono 2015-01-22 23:12:35 +01:00
parent eb4bcf9331
commit 35ab3a28fd
15 changed files with 241 additions and 16 deletions

View File

@ -21,7 +21,7 @@ public byte[] ComputeMd5(string path)
{ {
using (var md5 = MD5.Create()) using (var md5 = MD5.Create())
{ {
using (var stream = _diskProvider.StreamFile(path)) using (var stream = _diskProvider.OpenReadStream(path))
{ {
return md5.ComputeHash(stream); return md5.ComputeHash(stream);
} }

View File

@ -421,7 +421,7 @@ public string GetVolumeLabel(string path)
return driveInfo.VolumeLabel; return driveInfo.VolumeLabel;
} }
public FileStream StreamFile(string path) public FileStream OpenReadStream(string path)
{ {
if (!FileExists(path)) if (!FileExists(path))
{ {
@ -431,6 +431,11 @@ public FileStream StreamFile(string path)
return new FileStream(path, FileMode.Open, FileAccess.Read); return new FileStream(path, FileMode.Open, FileAccess.Read);
} }
public FileStream OpenWriteStream(string path)
{
return new FileStream(path, FileMode.Create);
}
public List<DriveInfo> GetDrives() public List<DriveInfo> GetDrives()
{ {
return DriveInfo.GetDrives() return DriveInfo.GetDrives()

View File

@ -45,7 +45,8 @@ public interface IDiskProvider
void EmptyFolder(string path); void EmptyFolder(string path);
string[] GetFixedDrives(); string[] GetFixedDrives();
string GetVolumeLabel(string path); string GetVolumeLabel(string path);
FileStream StreamFile(string path); FileStream OpenReadStream(string path);
FileStream OpenWriteStream(string path);
List<DriveInfo> GetDrives(); List<DriveInfo> GetDrives();
List<DirectoryInfo> GetDirectoryInfos(string path); List<DirectoryInfo> GetDirectoryInfos(string path);
List<FileInfo> GetFileInfos(string path); List<FileInfo> GetFileInfos(string path);

View File

@ -1,4 +1,5 @@
using System.IO; using System;
using System.IO;
namespace NzbDrone.Common.Extensions namespace NzbDrone.Common.Extensions
{ {

View File

@ -56,7 +56,7 @@ public void should_not_process_non_image_files()
Subject.Clean(); Subject.Clean();
Mocker.GetMock<IDiskProvider>().Verify(c => c.StreamFile(It.IsAny<string>()), Times.Never()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenReadStream(It.IsAny<string>()), Times.Never());
} }
@ -67,7 +67,7 @@ public void should_not_process_images_before_tvdb_switch()
Subject.Clean(); Subject.Clean();
Mocker.GetMock<IDiskProvider>().Verify(c => c.StreamFile(It.IsAny<string>()), Times.Never()); Mocker.GetMock<IDiskProvider>().Verify(c => c.OpenReadStream(It.IsAny<string>()), Times.Never());
} }
@ -107,7 +107,7 @@ public void should_delete_html_images()
_metaData.First().Type = MetadataType.SeriesImage; _metaData.First().Type = MetadataType.SeriesImage;
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.StreamFile(imagePath)) .Setup(c => c.OpenReadStream(imagePath))
.Returns(new FileStream("Files\\html_image.jpg".AsOsAgnostic(), FileMode.Open, FileAccess.Read)); .Returns(new FileStream("Files\\html_image.jpg".AsOsAgnostic(), FileMode.Open, FileAccess.Read));
@ -129,7 +129,7 @@ public void should_delete_empty_images()
_metaData.First().RelativePath = "Season\\image.jpg".AsOsAgnostic(); _metaData.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.StreamFile(imagePath)) .Setup(c => c.OpenReadStream(imagePath))
.Returns(new FileStream("Files\\emptyfile.txt".AsOsAgnostic(), FileMode.Open, FileAccess.Read)); .Returns(new FileStream("Files\\emptyfile.txt".AsOsAgnostic(), FileMode.Open, FileAccess.Read));
@ -149,7 +149,7 @@ public void should_not_delete_non_html_files()
_metaData.First().RelativePath = "Season\\image.jpg".AsOsAgnostic(); _metaData.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
.Setup(c => c.StreamFile(imagePath)) .Setup(c => c.OpenReadStream(imagePath))
.Returns(new FileStream("Files\\Queue.txt".AsOsAgnostic(), FileMode.Open, FileAccess.Read)); .Returns(new FileStream("Files\\Queue.txt".AsOsAgnostic(), FileMode.Open, FileAccess.Read));

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Crypto;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.MediaCoverTests
{
[TestFixture]
public class ImageResizerFixture : CoreTest<ImageResizer>
{
[SetUp]
public void SetUp()
{
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.OpenReadStream(It.IsAny<string>()))
.Returns<string>(s => new FileStream(s, FileMode.Open));
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.OpenWriteStream(It.IsAny<string>()))
.Returns<string>(s => new FileStream(s, FileMode.Create));
}
[Test]
public void should_resize_image()
{
var mainFile = Path.Combine(TempFolder, "logo.png");
var resizedFile = Path.Combine(TempFolder, "logo-170.png");
File.Copy(@"Files/1024.png", mainFile);
Subject.Resize(mainFile, resizedFile, 170);
var fileInfo = new FileInfo(resizedFile);
fileInfo.Exists.Should().BeTrue();
fileInfo.Length.Should().BeInRange(1000, 30000);
var image = System.Drawing.Image.FromFile(resizedFile);
image.Height.Should().Be(170);
image.Width.Should().Be(170);
}
}
}

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@ -7,17 +9,25 @@
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using System.Linq; using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Core.Test.MediaCoverTests namespace NzbDrone.Core.Test.MediaCoverTests
{ {
[TestFixture] [TestFixture]
public class MediaCoverServiceFixture : CoreTest<MediaCoverService> public class MediaCoverServiceFixture : CoreTest<MediaCoverService>
{ {
Series _series;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
Mocker.SetConstant<IAppFolderInfo>(new AppFolderInfo(Mocker.Resolve<IStartupContext>())); Mocker.SetConstant<IAppFolderInfo>(new AppFolderInfo(Mocker.Resolve<IStartupContext>()));
_series = Builder<Series>.CreateNew()
.With(v => v.Id = 2)
.With(v => v.Images = new List<MediaCover.MediaCover> { new MediaCover.MediaCover(MediaCoverTypes.Poster, "") })
.Build();
} }
[Test] [Test]
@ -55,5 +65,55 @@ public void should_convert_media_urls_to_local_without_time_if_file_doesnt_exist
covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg"); covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg");
} }
[Test]
public void should_resize_covers_if_main_downloaded()
{
Mocker.GetMock<ICoverExistsSpecification>()
.Setup(v => v.AlreadyExists(It.IsAny<string>(), It.IsAny<string>()))
.Returns(false);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FileExists(It.IsAny<string>()))
.Returns(true);
Subject.HandleAsync(new SeriesUpdatedEvent(_series));
Mocker.GetMock<IImageResizer>()
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
}
[Test]
public void should_resize_covers_if_missing()
{
Mocker.GetMock<ICoverExistsSpecification>()
.Setup(v => v.AlreadyExists(It.IsAny<string>(), It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FileExists(It.IsAny<string>()))
.Returns(false);
Subject.HandleAsync(new SeriesUpdatedEvent(_series));
Mocker.GetMock<IImageResizer>()
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
}
[Test]
public void should_not_resize_covers_if_exists()
{
Mocker.GetMock<ICoverExistsSpecification>()
.Setup(v => v.AlreadyExists(It.IsAny<string>(), It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FileExists(It.IsAny<string>()))
.Returns(true);
Subject.HandleAsync(new SeriesUpdatedEvent(_series));
Mocker.GetMock<IImageResizer>()
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Never());
}
} }
} }

View File

@ -74,6 +74,7 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -215,6 +216,7 @@
<Compile Include="JobTests\JobRepositoryFixture.cs" /> <Compile Include="JobTests\JobRepositoryFixture.cs" />
<Compile Include="JobTests\TestJobs.cs" /> <Compile Include="JobTests\TestJobs.cs" />
<Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" /> <Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" />
<Compile Include="MediaCoverTests\ImageResizerFixture.cs" />
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" /> <Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
<Compile Include="MediaFiles\DiskScanServiceTests\ScanFixture.cs" /> <Compile Include="MediaFiles\DiskScanServiceTests\ScanFixture.cs" />
<Compile Include="MediaFiles\DownloadedEpisodesCommandServiceFixture.cs" /> <Compile Include="MediaFiles\DownloadedEpisodesCommandServiceFixture.cs" />
@ -348,6 +350,10 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="..\..\Logo\1024.png">
<Link>Files\1024.png</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="..\Libraries\Sqlite\sqlite3.dll"> <Content Include="..\Libraries\Sqlite\sqlite3.dll">
<Link>sqlite3.dll</Link> <Link>sqlite3.dll</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>

View File

@ -69,7 +69,7 @@ private bool IsValid(string path)
{ {
var buffer = new byte[10]; var buffer = new byte[10];
using (var imageStream = _diskProvider.StreamFile(path)) using (var imageStream = _diskProvider.OpenReadStream(path))
{ {
if (imageStream.Length < buffer.Length) return false; if (imageStream.Length < buffer.Length) return false;
imageStream.Read(buffer, 0, buffer.Length); imageStream.Read(buffer, 0, buffer.Length);

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ImageResizer;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.MediaCover
{
public interface IImageResizer
{
void Resize(string source, string destination, int height);
}
public class ImageResizer : IImageResizer
{
private readonly IDiskProvider _diskProvider;
public ImageResizer(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public void Resize(string source, string destination, int height)
{
using (var sourceStream = _diskProvider.OpenReadStream(source))
{
using (var outputStream = _diskProvider.OpenWriteStream(destination))
{
var settings = new Instructions();
settings.Height = height;
var job = new ImageJob(sourceStream, outputStream, settings);
ImageBuilder.Current.Build(job);
}
}
}
}
}

View File

@ -17,7 +17,7 @@ namespace NzbDrone.Core.MediaCover
public interface IMapCoversToLocal public interface IMapCoversToLocal
{ {
void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers); void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers);
string GetCoverPath(int seriesId, MediaCoverTypes mediaCoverTypes); string GetCoverPath(int seriesId, MediaCoverTypes mediaCoverTypes, int? height = null);
} }
public class MediaCoverService : public class MediaCoverService :
@ -25,6 +25,7 @@ public class MediaCoverService :
IHandleAsync<SeriesDeletedEvent>, IHandleAsync<SeriesDeletedEvent>,
IMapCoversToLocal IMapCoversToLocal
{ {
private readonly IImageResizer _resizer;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly ICoverExistsSpecification _coverExistsSpecification; private readonly ICoverExistsSpecification _coverExistsSpecification;
@ -34,7 +35,8 @@ public class MediaCoverService :
private readonly string _coverRootFolder; private readonly string _coverRootFolder;
public MediaCoverService(IHttpClient httpClient, public MediaCoverService(IImageResizer resizer,
IHttpClient httpClient,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo, IAppFolderInfo appFolderInfo,
ICoverExistsSpecification coverExistsSpecification, ICoverExistsSpecification coverExistsSpecification,
@ -42,6 +44,7 @@ public MediaCoverService(IHttpClient httpClient,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
Logger logger) Logger logger)
{ {
_resizer = resizer;
_httpClient = httpClient; _httpClient = httpClient;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_coverExistsSpecification = coverExistsSpecification; _coverExistsSpecification = coverExistsSpecification;
@ -52,9 +55,11 @@ public MediaCoverService(IHttpClient httpClient,
_coverRootFolder = appFolderInfo.GetMediaCoverPath(); _coverRootFolder = appFolderInfo.GetMediaCoverPath();
} }
public string GetCoverPath(int seriesId, MediaCoverTypes coverTypes) public string GetCoverPath(int seriesId, MediaCoverTypes coverTypes, int? height = null)
{ {
return Path.Combine(GetSeriesCoverPath(seriesId), coverTypes.ToString().ToLower() + ".jpg"); var heightSuffix = height.HasValue ? "-" + height.ToString() : "";
return Path.Combine(GetSeriesCoverPath(seriesId), coverTypes.ToString().ToLower() + heightSuffix + ".jpg");
} }
public void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers) public void ConvertToLocalUrls(int seriesId, IEnumerable<MediaCover> covers)
@ -88,6 +93,11 @@ private void EnsureCovers(Series series)
if (!_coverExistsSpecification.AlreadyExists(cover.Url, fileName)) if (!_coverExistsSpecification.AlreadyExists(cover.Url, fileName))
{ {
DownloadCover(series, cover); DownloadCover(series, cover);
EnsureResizedCovers(series, cover, true);
}
else
{
EnsureResizedCovers(series, cover, false);
} }
} }
catch (WebException e) catch (WebException e)
@ -109,6 +119,44 @@ private void DownloadCover(Series series, MediaCover cover)
_httpClient.DownloadFile(cover.Url, fileName); _httpClient.DownloadFile(cover.Url, fileName);
} }
private void EnsureResizedCovers(Series series, MediaCover cover, bool forceResize)
{
int[] heights;
switch (cover.CoverType)
{
default:
return;
case MediaCoverTypes.Poster:
case MediaCoverTypes.Headshot:
heights = new[] { 500, 250 };
break;
case MediaCoverTypes.Banner:
heights = new[] { 70, 35 };
break;
case MediaCoverTypes.Fanart:
case MediaCoverTypes.Screenshot:
heights = new[] { 360, 180 };
break;
}
foreach (var height in heights)
{
var mainFileName = GetCoverPath(series.Id, cover.CoverType);
var resizeFileName = GetCoverPath(series.Id, cover.CoverType, height);
if (forceResize || !_diskProvider.FileExists(resizeFileName))
{
_logger.Debug("Resizing {0}-{1} for {2}", cover.CoverType, height, series);
_resizer.Resize(mainFileName, resizeFileName, height);
}
}
}
public void HandleAsync(SeriesUpdatedEvent message) public void HandleAsync(SeriesUpdatedEvent message)
{ {
EnsureCovers(message.Series); EnsureCovers(message.Series);

View File

@ -72,6 +72,10 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\Growl.CoreLibrary.dll</HintPath> <HintPath>..\Libraries\Growl.CoreLibrary.dll</HintPath>
</Reference> </Reference>
<Reference Include="ImageResizer, Version=3.4.3.103, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ImageResizer.3.4.3\lib\ImageResizer.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -522,6 +526,7 @@
<Compile Include="Lifecycle\LifecycleService.cs" /> <Compile Include="Lifecycle\LifecycleService.cs" />
<Compile Include="MediaCover\CoverAlreadyExistsSpecification.cs" /> <Compile Include="MediaCover\CoverAlreadyExistsSpecification.cs" />
<Compile Include="MediaCover\MediaCover.cs" /> <Compile Include="MediaCover\MediaCover.cs" />
<Compile Include="MediaCover\ImageResizer.cs" />
<Compile Include="MediaCover\MediaCoverService.cs" /> <Compile Include="MediaCover\MediaCoverService.cs" />
<Compile Include="MediaCover\MediaCoversUpdatedEvent.cs" /> <Compile Include="MediaCover\MediaCoversUpdatedEvent.cs" />
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" /> <Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />

View File

@ -19,7 +19,7 @@ public UpdateVerification(IDiskProvider diskProvider)
public Boolean Verify(UpdatePackage updatePackage, String packagePath) public Boolean Verify(UpdatePackage updatePackage, String packagePath)
{ {
using (var fileStream = _diskProvider.StreamFile(packagePath)) using (var fileStream = _diskProvider.OpenReadStream(packagePath))
{ {
var hash = fileStream.SHA256Hash(); var hash = fileStream.SHA256Hash();

View File

@ -3,6 +3,7 @@
<package id="FluentMigrator" version="1.3.1.0" targetFramework="net40" /> <package id="FluentMigrator" version="1.3.1.0" targetFramework="net40" />
<package id="FluentMigrator.Runner" version="1.3.1.0" targetFramework="net40" /> <package id="FluentMigrator.Runner" version="1.3.1.0" targetFramework="net40" />
<package id="FluentValidation" version="5.5.0.0" targetFramework="net40" /> <package id="FluentValidation" version="5.5.0.0" targetFramework="net40" />
<package id="ImageResizer" version="3.4.3" targetFramework="net40" />
<package id="MediaInfoNet" version="0.3" targetFramework="net40" /> <package id="MediaInfoNet" version="0.3" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" /> <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
<package id="NLog" version="2.1.0" targetFramework="net40" /> <package id="NLog" version="2.1.0" targetFramework="net40" />

View File

@ -34,10 +34,16 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Core", "NzbDrone.Core\NzbDrone.Core.csproj", "{FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Core", "NzbDrone.Core\NzbDrone.Core.csproj", "{FF5EE3B6-913B-47CE-9CEB-11C51B4E1205}"
ProjectSection(ProjectDependencies) = postProject
{0CC493D7-0A9F-4199-9615-0A977945D716} = {0CC493D7-0A9F-4199-9615-0A977945D716}
EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update", "NzbDrone.Update\NzbDrone.Update.csproj", "{4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update", "NzbDrone.Update\NzbDrone.Update.csproj", "{4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Common", "NzbDrone.Common\NzbDrone.Common.csproj", "{F2BE0FDF-6E47-4827-A420-DD4EF82407F8}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Common", "NzbDrone.Common\NzbDrone.Common.csproj", "{F2BE0FDF-6E47-4827-A420-DD4EF82407F8}"
ProjectSection(ProjectDependencies) = postProject
{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB} = {9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}
EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E6B3CBE-1578-41C1-9BF9-78D818740BE9}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E6B3CBE-1578-41C1-9BF9-78D818740BE9}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
@ -81,6 +87,9 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesCore", "LogentriesCore\LogentriesCore.csproj", "{90D6E9FC-7B88-4E1B-B018-8FA742274558}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesCore", "LogentriesCore\LogentriesCore.csproj", "{90D6E9FC-7B88-4E1B-B018-8FA742274558}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesNLog", "LogentriesNLog\LogentriesNLog.csproj", "{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesNLog", "LogentriesNLog\LogentriesNLog.csproj", "{9DC31DE3-79FF-47A8-96B4-6BA18F6BB1CB}"
ProjectSection(ProjectDependencies) = postProject
{90D6E9FC-7B88-4E1B-B018-8FA742274558} = {90D6E9FC-7B88-4E1B-B018-8FA742274558}
EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TVDBSharp", "TVDBSharp\TVDBSharp.csproj", "{0CC493D7-0A9F-4199-9615-0A977945D716}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TVDBSharp", "TVDBSharp\TVDBSharp.csproj", "{0CC493D7-0A9F-4199-9615-0A977945D716}"
EndProject EndProject