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:
parent
eb4bcf9331
commit
35ab3a28fd
@ -21,7 +21,7 @@ public byte[] ComputeMd5(string path)
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
using (var stream = _diskProvider.StreamFile(path))
|
||||
using (var stream = _diskProvider.OpenReadStream(path))
|
||||
{
|
||||
return md5.ComputeHash(stream);
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ public string GetVolumeLabel(string path)
|
||||
return driveInfo.VolumeLabel;
|
||||
}
|
||||
|
||||
public FileStream StreamFile(string path)
|
||||
public FileStream OpenReadStream(string path)
|
||||
{
|
||||
if (!FileExists(path))
|
||||
{
|
||||
@ -431,6 +431,11 @@ public FileStream StreamFile(string path)
|
||||
return new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public FileStream OpenWriteStream(string path)
|
||||
{
|
||||
return new FileStream(path, FileMode.Create);
|
||||
}
|
||||
|
||||
public List<DriveInfo> GetDrives()
|
||||
{
|
||||
return DriveInfo.GetDrives()
|
||||
|
@ -45,7 +45,8 @@ public interface IDiskProvider
|
||||
void EmptyFolder(string path);
|
||||
string[] GetFixedDrives();
|
||||
string GetVolumeLabel(string path);
|
||||
FileStream StreamFile(string path);
|
||||
FileStream OpenReadStream(string path);
|
||||
FileStream OpenWriteStream(string path);
|
||||
List<DriveInfo> GetDrives();
|
||||
List<DirectoryInfo> GetDirectoryInfos(string path);
|
||||
List<FileInfo> GetFileInfos(string path);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace NzbDrone.Common.Extensions
|
||||
{
|
||||
|
@ -56,7 +56,7 @@ public void should_not_process_non_image_files()
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ public void should_delete_empty_images()
|
||||
_metaData.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.StreamFile(imagePath))
|
||||
.Setup(c => c.OpenReadStream(imagePath))
|
||||
.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();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.StreamFile(imagePath))
|
||||
.Setup(c => c.OpenReadStream(imagePath))
|
||||
.Returns(new FileStream("Files\\Queue.txt".AsOsAgnostic(), FileMode.Open, FileAccess.Read));
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@ -7,17 +9,25 @@
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class MediaCoverServiceFixture : CoreTest<MediaCoverService>
|
||||
{
|
||||
Series _series;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
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]
|
||||
@ -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");
|
||||
}
|
||||
|
||||
[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());
|
||||
}
|
||||
}
|
||||
}
|
@ -74,6 +74,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@ -215,6 +216,7 @@
|
||||
<Compile Include="JobTests\JobRepositoryFixture.cs" />
|
||||
<Compile Include="JobTests\TestJobs.cs" />
|
||||
<Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" />
|
||||
<Compile Include="MediaCoverTests\ImageResizerFixture.cs" />
|
||||
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\DiskScanServiceTests\ScanFixture.cs" />
|
||||
<Compile Include="MediaFiles\DownloadedEpisodesCommandServiceFixture.cs" />
|
||||
@ -348,6 +350,10 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\Logo\1024.png">
|
||||
<Link>Files\1024.png</Link>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\Libraries\Sqlite\sqlite3.dll">
|
||||
<Link>sqlite3.dll</Link>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
|
@ -69,7 +69,7 @@ private bool IsValid(string path)
|
||||
{
|
||||
var buffer = new byte[10];
|
||||
|
||||
using (var imageStream = _diskProvider.StreamFile(path))
|
||||
using (var imageStream = _diskProvider.OpenReadStream(path))
|
||||
{
|
||||
if (imageStream.Length < buffer.Length) return false;
|
||||
imageStream.Read(buffer, 0, buffer.Length);
|
||||
|
39
src/NzbDrone.Core/MediaCover/ImageResizer.cs
Normal file
39
src/NzbDrone.Core/MediaCover/ImageResizer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ namespace NzbDrone.Core.MediaCover
|
||||
public interface IMapCoversToLocal
|
||||
{
|
||||
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 :
|
||||
@ -25,6 +25,7 @@ public class MediaCoverService :
|
||||
IHandleAsync<SeriesDeletedEvent>,
|
||||
IMapCoversToLocal
|
||||
{
|
||||
private readonly IImageResizer _resizer;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly ICoverExistsSpecification _coverExistsSpecification;
|
||||
@ -34,7 +35,8 @@ public class MediaCoverService :
|
||||
|
||||
private readonly string _coverRootFolder;
|
||||
|
||||
public MediaCoverService(IHttpClient httpClient,
|
||||
public MediaCoverService(IImageResizer resizer,
|
||||
IHttpClient httpClient,
|
||||
IDiskProvider diskProvider,
|
||||
IAppFolderInfo appFolderInfo,
|
||||
ICoverExistsSpecification coverExistsSpecification,
|
||||
@ -42,6 +44,7 @@ public MediaCoverService(IHttpClient httpClient,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
_resizer = resizer;
|
||||
_httpClient = httpClient;
|
||||
_diskProvider = diskProvider;
|
||||
_coverExistsSpecification = coverExistsSpecification;
|
||||
@ -52,9 +55,11 @@ public MediaCoverService(IHttpClient httpClient,
|
||||
_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)
|
||||
@ -88,6 +93,11 @@ private void EnsureCovers(Series series)
|
||||
if (!_coverExistsSpecification.AlreadyExists(cover.Url, fileName))
|
||||
{
|
||||
DownloadCover(series, cover);
|
||||
EnsureResizedCovers(series, cover, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnsureResizedCovers(series, cover, false);
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
@ -109,6 +119,44 @@ private void DownloadCover(Series series, MediaCover cover)
|
||||
_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)
|
||||
{
|
||||
EnsureCovers(message.Series);
|
||||
|
@ -72,6 +72,10 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libraries\Growl.CoreLibrary.dll</HintPath>
|
||||
</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">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
@ -522,6 +526,7 @@
|
||||
<Compile Include="Lifecycle\LifecycleService.cs" />
|
||||
<Compile Include="MediaCover\CoverAlreadyExistsSpecification.cs" />
|
||||
<Compile Include="MediaCover\MediaCover.cs" />
|
||||
<Compile Include="MediaCover\ImageResizer.cs" />
|
||||
<Compile Include="MediaCover\MediaCoverService.cs" />
|
||||
<Compile Include="MediaCover\MediaCoversUpdatedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||
|
@ -19,7 +19,7 @@ public UpdateVerification(IDiskProvider diskProvider)
|
||||
|
||||
public Boolean Verify(UpdatePackage updatePackage, String packagePath)
|
||||
{
|
||||
using (var fileStream = _diskProvider.StreamFile(packagePath))
|
||||
using (var fileStream = _diskProvider.OpenReadStream(packagePath))
|
||||
{
|
||||
var hash = fileStream.SHA256Hash();
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<package id="FluentMigrator" 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="ImageResizer" version="3.4.3" targetFramework="net40" />
|
||||
<package id="MediaInfoNet" version="0.3" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
|
||||
<package id="NLog" version="2.1.0" targetFramework="net40" />
|
||||
|
@ -34,10 +34,16 @@ EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceUninstall", "ServiceHelpers\ServiceUninstall\ServiceUninstall.csproj", "{700D0B95-95CD-43F3-B6C9-FAA0FC1358D4}"
|
||||
EndProject
|
||||
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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NzbDrone.Update", "NzbDrone.Update\NzbDrone.Update.csproj", "{4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7}"
|
||||
EndProject
|
||||
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
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E6B3CBE-1578-41C1-9BF9-78D818740BE9}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
@ -81,6 +87,9 @@ EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesCore", "LogentriesCore\LogentriesCore.csproj", "{90D6E9FC-7B88-4E1B-B018-8FA742274558}"
|
||||
EndProject
|
||||
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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TVDBSharp", "TVDBSharp\TVDBSharp.csproj", "{0CC493D7-0A9F-4199-9615-0A977945D716}"
|
||||
EndProject
|
||||
|
Loading…
Reference in New Issue
Block a user