diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 05e6a9416..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "*.yaml": "home-assistant" - } -} \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c7c752b4e..a6c36a266 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -265,7 +265,6 @@ stages: - bash: ./build.sh --packages --enable-bsd displayName: Create Packages - bash: | - find . -name "fpcalc" -exec chmod a+x {} \; find . -name "Readarr" -exec chmod a+x {} \; find . -name "Readarr.Update" -exec chmod a+x {} \; displayName: Set executable bits @@ -453,10 +452,6 @@ stages: - powershell: Set-Service SCardSvr -StartupType Manual displayName: Enable Windows Test Service condition: and(succeeded(), eq(variables['osName'], 'Windows')) - - bash: | - chmod a+x _tests/fpcalc - displayName: Make fpcalc Executable - condition: and(succeeded(), or(eq(variables['osName'], 'Mac'), eq(variables['testName'], 'LinuxCore'))) - bash: find ${TESTSFOLDER} -name "Readarr.Test.Dummy" -exec chmod a+x {} \; displayName: Make Test Dummy Executable condition: and(succeeded(), ne(variables['osName'], 'Windows')) diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index eb8f841a6..000000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -nzbdrone {version} {branch}; urgency=low - - * Automatic Release. - - -- NzbDrone Mon, 26 Aug 2013 00:00:00 -0700 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 45a4fb75d..000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -8 diff --git a/debian/control b/debian/control deleted file mode 100644 index d233d6cdc..000000000 --- a/debian/control +++ /dev/null @@ -1,12 +0,0 @@ -Section: web -Priority: optional -Maintainer: Sonarr -Source: nzbdrone -Homepage: https://readarr.com -Vcs-Git: git@github.com:readarr/Readarr.git -Vcs-Browser: https://github.com/readarr/Readarr - -Package: nzbdrone -Architecture: all -Depends: libmono-cil-dev (>= 3.2), sqlite3 (>= 3.7), mediainfo (>= 0.7.52) -Description: Readarr is a music collection manager diff --git a/debian/copyright b/debian/copyright deleted file mode 100755 index d72225b4b..000000000 --- a/debian/copyright +++ /dev/null @@ -1,24 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: nzbdrone -Source: https://github.com/readarr/Readarr - -Files: * -Copyright: 2010-2016 Readarr - -License: GPL-3.0+ - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . - . - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/debian/install b/debian/install deleted file mode 100755 index 1810b9185..000000000 --- a/debian/install +++ /dev/null @@ -1 +0,0 @@ -nzbdrone_bin/* opt/NzbDrone diff --git a/debian/rules b/debian/rules deleted file mode 100755 index b760bee7f..000000000 --- a/debian/rules +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -%: - dh $@ diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 4cf15bc72..a6b5fc230 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,4 +1,3 @@ - diff --git a/src/NzbDrone.Api/Blocklist/BlocklistModule.cs b/src/NzbDrone.Api/Blocklist/BlocklistModule.cs deleted file mode 100644 index 377ac4f78..000000000 --- a/src/NzbDrone.Api/Blocklist/BlocklistModule.cs +++ /dev/null @@ -1,30 +0,0 @@ -using NzbDrone.Core.Blocklisting; -using NzbDrone.Core.Datastore; -using Sonarr.Http; - -namespace NzbDrone.Api.Blocklist -{ - public class BlocklistModule : SonarrRestModule - { - private readonly BlocklistService _blocklistService; - - public BlocklistModule(BlocklistService blocklistService) - { - _blocklistService = blocklistService; - GetResourcePaged = Blocklist; - DeleteResource = DeleteBlockList; - } - - private PagingResource Blocklist(PagingResource pagingResource) - { - var pagingSpec = pagingResource.MapToPagingSpec("id", SortDirection.Ascending); - - return ApplyToPage(_blocklistService.Paged, pagingSpec, BlocklistResourceMapper.MapToResource); - } - - private void DeleteBlockList(int id) - { - _blocklistService.Delete(id); - } - } -} diff --git a/src/NzbDrone.Api/Blocklist/BlocklistResource.cs b/src/NzbDrone.Api/Blocklist/BlocklistResource.cs deleted file mode 100644 index bdfe85b2c..000000000 --- a/src/NzbDrone.Api/Blocklist/BlocklistResource.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using Sonarr.Http.REST; -using NzbDrone.Core.Qualities; -using NzbDrone.Api.Series; -using NzbDrone.Core.Indexers; -using NzbDrone.Core.Languages; - -namespace NzbDrone.Api.Blocklist -{ - public class BlocklistResource : RestResource - { - public int SeriesId { get; set; } - public List EpisodeIds { get; set; } - public string SourceTitle { get; set; } - public QualityModel Quality { get; set; } - public DateTime Date { get; set; } - public DownloadProtocol Protocol { get; set; } - public string Indexer { get; set; } - public string Message { get; set; } - public Language Language { get; set; } - - public SeriesResource Series { get; set; } - } - - public static class BlocklistResourceMapper - { - public static BlocklistResource MapToResource(this Core.Blocklisting.Blocklist model) - { - if (model == null) return null; - - return new BlocklistResource - { - Id = model.Id, - - SeriesId = model.SeriesId, - EpisodeIds = model.EpisodeIds, - SourceTitle = model.SourceTitle, - Quality = model.Quality, - Date = model.Date, - Protocol = model.Protocol, - Indexer = model.Indexer, - Message = model.Message, - - Series = model.Series.ToResource() - }; - } - } -} diff --git a/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Identification/IdentificationServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Identification/IdentificationServiceFixture.cs index e3baae01f..7bacb6922 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Identification/IdentificationServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Identification/IdentificationServiceFixture.cs @@ -125,19 +125,6 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification return _authorService.FindById(foreignAuthorId); } - private void GivenFingerprints(List fingerprints) - { - Mocker.GetMock().Setup(x => x.AllowFingerprinting).Returns(AllowFingerprinting.AllFiles); - Mocker.GetMock().Setup(x => x.IsSetup()).Returns(true); - - Mocker.GetMock() - .Setup(x => x.Lookup(It.IsAny>(), It.IsAny())) - .Callback((List track, double thres) => - { - track.ForEach(x => x.AcoustIdResults = fingerprints.SingleOrDefault(f => f.Path == x.Path).AcoustIdResults); - }); - } - public static class IdTestCaseFactory { // for some reason using Directory.GetFiles causes nUnit to error @@ -182,11 +169,6 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification FileTrackInfo = x.FileTrackInfo }).ToList(); - if (testcase.Fingerprints != null) - { - GivenFingerprints(testcase.Fingerprints); - } - var config = new ImportDecisionMakerConfig { NewDownload = testcase.NewDownload, diff --git a/src/NzbDrone.Core.Test/ParserTests/FingerprintingServiceFixture.cs b/src/NzbDrone.Core.Test/ParserTests/FingerprintingServiceFixture.cs deleted file mode 100644 index 6670b006a..000000000 --- a/src/NzbDrone.Core.Test/ParserTests/FingerprintingServiceFixture.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using FluentAssertions; -using Moq; -using Newtonsoft.Json; -using NUnit.Framework; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Core.Parser; -using NzbDrone.Core.Parser.Model; -using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using static NzbDrone.Core.Parser.FingerprintingService; - -namespace NzbDrone.Core.Test.ParserTests -{ - [TestFixture] - public class FingerprintingServiceFixture : CoreTest - { - public class FingerPrintTest - { - public string Request { get; set; } - public string Response { get; set; } - } - - [SetUp] - public void Setup() - { - UseAcoustidResponses(); - /* UseRealHttp(); */ - } - - public void UseAcoustidResponses() - { - // responses were generated by editing HttpClient to write out the content bytes as a string - // using System.Text.Encoding.UTF8.GetString(request.ContentData.Decompress()); - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Fingerprinting", "AcoustidResponses.json"); - var responses = JsonConvert.DeserializeObject>(File.ReadAllText(path)); - - foreach (var response in responses) - { - Mocker.GetMock() - .Setup(o => o.Post( - It.Is(v => - v.Url.Equals(new HttpUri("https://api.acoustid.org/v2/lookup")) && - v.Headers.Contains(new KeyValuePair("Content-Encoding", "gzip")) && - v.Headers.ContentType == "application/x-www-form-urlencoded" && - Encoding.UTF8.GetString(v.ContentData.Decompress()) == response.Request))) - .Returns(r => new HttpResponse(new HttpResponse(r, new HttpHeader(), response.Response))); - } - } - - [Test] - public void should_parse_fpcalc_json() - { - var json = "{\"duration\": 229.29, \"fingerprint\": \"AQADtFMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-I2mPwd0PeQ8yHsByu4zqHPkfzo4-OtE6R7Dq-5fg3o-kuoVU84VGLIDkNqzEFNt1x7RvOHO7wf8hznDz0KA6F6-g1uE2OPseFvKh-9MGp4we7LLmIhxE1JHeDcLyOUD8uDTozND_apQvyiQ9yQcoRxisuBxeVDd-LRrGO-0xRKwuPh4ivHP8GUQ_ig87RN0czSkf0xEMNcRzxw8elHKIikcKlB5bGY-J9PImJ64K4PCDD7rh8_Ogvo5kOmU0RnjmcC2na9LiGbpKhC48RJvo2hI-HD80sVONx58nQ49CfLtCj59CTBz8eDZ4O7fHwBw-hPhJ0HhqlU0h9XB9qKsh_fNmRiTz-qPido6l3lB0X_DiS90QOOxdxbwJ94XqjwmKyHBeLHzfyH1MuaM9xibgeCe2O5gv-QzUz5NtRay8s7Tj6E1cSHH2eIa0tJB9OBVXa4g9-1M6DOsPTo3wwJQo3PA_4TMh_JJEPb4OzHSUTbcIvPCHcI4-gE7mOp8RxRyX6ySvM2EbJbhEeHVeKZOkR_hJKKTvM_SiPu9FhOUes6kJySTneozfO0HiObSy-7AXDp8gbJMd-4TmebB9KiYKfHNWPG8c9JGvUI5Tz4Xle3FEkhD-01DFy4gnKoOTxw23wOfjRjNKPZNp2Io8OpxmuJsW-7DgvoXYenEEtCT2aKDfIMDv-TEJ0JMtxoZk04Uqi4Ic_HLGP5JLRC80_XFJC9JnwjpNRjTueRSuS_4h4NIfzBl00E5-mo3ckNB-FPIE-5BlO9UL5Dudx5vikFB5DF-FKI7myxPjj4Yzw7OjRxOHxB8f3o9wO34V__IR5UkSf7LiOPhLSL-DR4MKlo5zwr8LFAf8h_oBtVTj8GIcAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARBgmADDNKIEAEoAgAAAQDBAgCHJCAEGG0QkQAaZgAAkpAkBAGImAgIYI5AoQAAiBBiCDMASGIYQAoB4QgCAlBIHFIICaAIM4aJawAxFIBDAFGGEA5AUQAgZhCTgJBgEKAACEMI4gwRRwQDAEEIQFEIaKIQYQBgYgBCjiGgAHEUQGYAIwwQASSylCjgJKMI8AIhIAAgAQwBBChhCIKAyOAVIIZAYBBihIIiBAACKMUUhI6JYAAigBADFAiAGBAhoZApRRQwABAiCCAGGcAQUIaBQBhgjBDACEEWSEsYAQYBIAVAACCmDAhEUAEEEQJhQA\"}"; - - var result = Subject.ParseFpcalcJsonOutput(json); - - result.Duration.Should().Be(229.29); - result.Fingerprint.Should().Be("AQADtFMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-I2mPwd0PeQ8yHsByu4zqHPkfzo4-OtE6R7Dq-5fg3o-kuoVU84VGLIDkNqzEFNt1x7RvOHO7wf8hznDz0KA6F6-g1uE2OPseFvKh-9MGp4we7LLmIhxE1JHeDcLyOUD8uDTozND_apQvyiQ9yQcoRxisuBxeVDd-LRrGO-0xRKwuPh4ivHP8GUQ_ig87RN0czSkf0xEMNcRzxw8elHKIikcKlB5bGY-J9PImJ64K4PCDD7rh8_Ogvo5kOmU0RnjmcC2na9LiGbpKhC48RJvo2hI-HD80sVONx58nQ49CfLtCj59CTBz8eDZ4O7fHwBw-hPhJ0HhqlU0h9XB9qKsh_fNmRiTz-qPido6l3lB0X_DiS90QOOxdxbwJ94XqjwmKyHBeLHzfyH1MuaM9xibgeCe2O5gv-QzUz5NtRay8s7Tj6E1cSHH2eIa0tJB9OBVXa4g9-1M6DOsPTo3wwJQo3PA_4TMh_JJEPb4OzHSUTbcIvPCHcI4-gE7mOp8RxRyX6ySvM2EbJbhEeHVeKZOkR_hJKKTvM_SiPu9FhOUes6kJySTneozfO0HiObSy-7AXDp8gbJMd-4TmebB9KiYKfHNWPG8c9JGvUI5Tz4Xle3FEkhD-01DFy4gnKoOTxw23wOfjRjNKPZNp2Io8OpxmuJsW-7DgvoXYenEEtCT2aKDfIMDv-TEJ0JMtxoZk04Uqi4Ic_HLGP5JLRC80_XFJC9JnwjpNRjTueRSuS_4h4NIfzBl00E5-mo3ckNB-FPIE-5BlO9UL5Dudx5vikFB5DF-FKI7myxPjj4Yzw7OjRxOHxB8f3o9wO34V__IR5UkSf7LiOPhLSL-DR4MKlo5zwr8LFAf8h_oBtVTj8GIcAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARBgmADDNKIEAEoAgAAAQDBAgCHJCAEGG0QkQAaZgAAkpAkBAGImAgIYI5AoQAAiBBiCDMASGIYQAoB4QgCAlBIHFIICaAIM4aJawAxFIBDAFGGEA5AUQAgZhCTgJBgEKAACEMI4gwRRwQDAEEIQFEIaKIQYQBgYgBCjiGgAHEUQGYAIwwQASSylCjgJKMI8AIhIAAgAQwBBChhCIKAyOAVIIZAYBBihIIiBAACKMUUhI6JYAAigBADFAiAGBAhoZApRRQwABAiCCAGGcAQUIaBQBhgjBDACEEWSEsYAQYBIAVAACCmDAhEUAEEEQJhQA"); - } - - [Test] - public void should_parse_fpcalc_text() - { - var text = @"FILE=Adele - 01 - 21 - Rolling in the Deep.flac -DURATION=229 -FINGERPRINT=AQAHJlMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-IehuDm92Q9xDzISyH67jOoc_R_OijI61TJLuObzn-zWi6S2gVT3jUIkhOw2pMgU13XPuGM4c7_B_yHCcPPYpD4Tp6DW6To89xIS-qH31w6vjBLksu4mFEDcndIByvI9SPS4PODM2PdumCfOKDXJByhPGKy8FFZcP3olGs4z5T1MrC4yHiK8e_QdSD-KBz9M3RjNIRPfFQQxxH_PBxKYeoSKRw6YGl8Zh4H09i4rogLg_IsDsuHz_6y2imQ2ZThGcO50KaNj2uoZtk6MJjhIm-DeHj4UMzC9V43Hky9Dj0pwv06Dn05MGPR4OnQ3s8_MFDqI8EnYdG6RRSH9eHmgryH192ZCKPPyp-52jqHWXHBT-O5D2Rw85F3JtAX7jeqLCYLMfF4seN_MeUC9pzXCKuR0K7o_mC_1DNDPl21NoLSzuO_sSVBEefZ0hrC8mHU0GVtviDH7XzoM7w9CgfTInCDc8DPhPyH0nkw9vgbEfJRJvwC08I98gj6ESu4ylx3FGJfvIKM7ZRsluER8eVIll6hL-EUsoOcz_K4250WM4Rq7qQXFKO9-iNMzSeYxuLL3vB8CnyBsmxX3iOJ9uHUqLgJ0f148ZxD8ka9QjlfHieF3cUCeEPLXWMnHiCMih5_HAbfA5-NKP0I5m2ncijw2mGq0mxLzvOS6idB2dQS0KPJsoNMsyOP5MQHclyXGgmTbiSKPjhD0fsI7lk9ELzD5eUEH0mvGONatyFZ9GK5D8iHs3hvEEXzcSn6egdCc1HIU-gD3mGU71QvsN5nDk-KYXH0EW40kiuLDH-eDgjPDt6NHF4PHjw_Si3w3fhHz9hnhTRJzuuI3wk-At4NLhw6Sgn_KtwccB_iD9gWxUOP8bhHb8HT0evRcJ_ouuC5oM0t0K_I_7gTUpwXI6RZ4fIE-kkynhzvMwFnzmI1MXeQ1xW9MqDHqkj3Fl0fDyeHa2iB9-CF2EuaD9yBWdi4cHjKEoCZzGPfOGhK8tx4kyHSh3SROODkIpRW4eW54J-NEckOZJGPH8S_MXX5HgiHj18MUMWj8UJ_SL-HL0HOxF0_MZ3xDDzoL_QKzr8gOGH8IH-Ii9-eE8s1Bc-7cS1EY3KHPON2D3axMa344eWx4JmH1dKnDxRUtvQ3DJO4spyaH8ORx9yLVlRNcbRH-4T3NERTXrwD4pJKoGvDlt9IeQS9Drcx7jEdHCqHdO2436Ea0cZIlkmBrmOx8WHK0eZC36Kylks47mNI8zEndAcFzleM2hWxkR_PMH14UOYH4V6ovvh4j7eGflx68H24P_gUsHx7fCNx7g2IX5QLpwW5FqWGDyH_vAVrCXgZ0F-iIqOSswe_ESPZqxRH9su6ISvoz2OR0Xt4Olx96CO43gl-CHqB7rxpzjR7EPlctDNQl6SoxJpIT3-wD_q4cmRB1qOPkbeKI3wa9ijBU9E-HSRL9uh4_7wKA1RK1GI5tFxGe0PMQmNf0iPPyIeHf_xJg9O5IeYv3geFuHJID96SRs-HGePG47xRsTFBfpxScthJ1Eq1D9Cwj-eLcZVH-5wwfvRN0b8BzvCPAE5HemWLOgqGfehHc2XNMj7oOxxpOijBDrBMES6ZclxesQzvBX8oD9e9IJ_tJOMagpzNNfBC4-OqTua96i3w6_RK-HR8DmSWULcxMOV43fwP2iuTMi14UwERUrI6MgX5J-S4BbmQ-yPPDn85DhxamIC_7hSPMf9IJmSuAhzYg9OUkrw6UHzoCdyfUjAHf05NGoWB2-InCeS2XFwH4we5ThODp2i7-Dn4BaHMJKSC7qObPKD5ktm1BS-oEyuBc1xXoiThTmSJ5Qx5VGHXmFwcnjjCJ6SIHmi3Mgf4EqHR7uC7xFOZQiZdUOy7MaNn8eHv4EZ6cFH4T_uI_mHvA9OxUEj1phEDTlzHP-D_UmIo3FIhCxRPeiX4wmuJEeeT2hCCslOPNjvBI80EqwUFE3xI9bICXpUBM0zfej0tPglnDeYXIuRH2KP_Ivw5LiUB1nictCdEvfRTTma73hyfNEjrEw-iLMS4-GFPWlCZPmOZuyPOcR_9JUGuyb64_iFL_hkxH6g7YiXF009PLlw7DkO_kHPFE2VrcSToVeQPkR16M3x-DjCE8ePH_mFhD8eocdxXiu6w2nC6ehxIkHe4cwMVlqOvfBTnJi6LNPR7B_4HOm-QE-OPW4i5DiPXM6E39AEH6Vz9MeRb8ePA7kh3ugRUnoERxH6CrVjfHvgx7BPo1aON8UlPEiupIgfBeuNShmoTTz-FCGpHMnNDp9wncF1XDqSPUeYxMf4ZMecHKd-8DrEHz--m3h6_Cr6ozluyRISh9ERH4d7nMcXBhPJB83xDZP-obGET1oRH8nzB2dYNCeO6Ua-7NDx7InwRyuaH6F148qSJ_jT4SyJ8BLRjBnk5EmG3KLQHdtJosyiJsFvoheyZKeQPMqOL0yk4jz847mEX3g61NfxBrXwWChPNGd0fAuq7ALV9EJ6aDx-hPlRH9eO0PrRHNehJzmKXxkhH-oKHz_S47iEzyJyHDr8RyjxFtV4iCoz4kj_glbh4xPyBR8P_UGYUcfDo9_hLwdv-Ee0EZdwCbqOnHjg_IeT4_ng4zDJD8ls5Ds-JniEx1sC58jxaNAp9LqhH2r8oIKe6LiOntByCbEjVnguR9gvXAmPc0HZo7k5_A7yGr9GaNnR49GFZwo0xDkcHj2uHL3RHEfeQbuI-3CP-yGq6cZPdB6xxT3-Ii-OK4Mr1I6D58MnPGJihDyaP9AV4kXIT2i4ZCeeHtWPX3jm4jh7pNJ6_PgiiM-DXMnxwEctxkap7YeDjsmJij6uBOYiJPuR48aPhyeOKb9RUQyeF8n7IecPJsyI8iVQ80RzjshTaHmD8J3w6EDVCk9zXOlxHM1lBX-RI_nRLwf_DP7hB5WOPwgbEeJb4algxgcvvIE14zhO4j0cKYRmLS_6HfxxHf0nzCz0H82DWsiDLxEndO3hP-jxo9-FMId-5A8-EndUBVX06Wj64yqOvN3wFb9DqNKGPjouAulROccfaUPEP8KTQ9cWPD_CHPXmDG9wXUb4Q8uFXA6eG4zawzochcd__INP9C2yHOIR_sLR5wqavHjU8Dji74Tma0jJ4MdF8B2-GH5mGXvhG-GhqPzQjDpygrFz2GGDn4iT69izEY7Q_7ieLZAVEU1Elsi_HB4DL8dk9fiWoelQnkF-KErErMSTNHikqCq0PrgmBeEp-HRU9CHCjIfmIdJTNFUmTQF7VE2EJqm0Is9SFeVyatj4IyQZXDl6NFWWDpeI3DtOY_SLJ8sM9k2QZ2huVMcTA4cAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARSABkmFECASIARQAAIBggQBDggASECKMVIgJIwwQQUAKChDAQAQMJEcwRIAQQAAlCBGEOCEEMA0A5IARBSAgCiUMCMQEEcdYoYQUglgpgCDDCAMoJIAIIxBRyEggCFAIECGEYQYQp4oBgCCAICSAKEUUMIgwIRAxQwDEEDCCOCsAEYIQBIpBUhhoFlGQcAUYgBAQAJIAhgAglFFEYGAGkEswIAAxSlEBAhABAGKWQktApAQRQBABigBIBAAMyNAQqpYACBgACBAHEOAMIEtIoAAgThBkCCCHIChMYAQYBYAUAgCAmTEgEEAEEUUIhNRAABgChCACCKAAEAAAQYwghCAAAAEJgMMEYCEhAAiADCAAFRAACOUKII4gBowwwECABgAJAIKgMoogJAwABQiFBODLECMSQAQYoYCRAAABgjBBGEUiAYQAR6ghiAhBKCFMGEeAFEIIAYBBDABEhFDKKIgOYoAQo4QgToElEAPIMIIAQtVZQgxQoBJIKAENGESSIFAQwgBAgADAAAMBEOGKIQMpJAAgQRCljKCGICKQAIQAYYwQXQCCgDBJECWIIGAgwxgRQRAnDhMMOGICMEAgYIYEiAhADCBGEMiMIAsQQoBAiBAgPiHBEGiMMIIoSoJAABCFJDAFEaKAIAIYyQJQBgigCBAMAgGIAQQYRIZBASAhDABEIIgLEEQA4JgCBSgAAnAEKIIYJoIAYAjAkQCAiCAEMIACYAYAIFDxxSgElGGAcEaGMkIQBBDlSEDFBFRKLAOEEJMIQBYgQgEAGAGEEEKIIcYAZIRChSDOLiAXMMGohUk4IYJFQCAkECCGWGCCIMMwAABATlCgghCjMGWCSEMIAAAigwjhjCAMICQCIEAIZA4gwTgACkGKMMEIVUEwABBzAmBnBlBKCSGIMAcAqpagFBUWCgBRIGCuYUYQhwAggggEIjjKKAyAAMwoE5owIziIiBCSGCAIMAEAoggxFCCAmmFTEWMKUYQgNQBhBgCAEjFNIKeOMQ4AwRYBBwAjGgDDAMQSMUUwAIqAR1jpIEEEEKGMEAkYIhBADQgBEqUFAFEqQIYI4JhSwwihRjUCAGAeQAYgAYrRhgBGkjEBACCEBAEYopIAwQCCGBDAAGUAAoooJJKByRkBDiJDCMa2UAQMYYRgQAGBFADBIGKEAYg4AgAgQSgAoHCFMCgCUAEY5BQBCxjMIEBBEEgAA -"; - - var result = Subject.ParseFpcalcTextOutput(text); - result.Duration.Should().Be(229); - result.Fingerprint.Should().Be("AQAHJlMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-IehuDm92Q9xDzISyH67jOoc_R_OijI61TJLuObzn-zWi6S2gVT3jUIkhOw2pMgU13XPuGM4c7_B_yHCcPPYpD4Tp6DW6To89xIS-qH31w6vjBLksu4mFEDcndIByvI9SPS4PODM2PdumCfOKDXJByhPGKy8FFZcP3olGs4z5T1MrC4yHiK8e_QdSD-KBz9M3RjNIRPfFQQxxH_PBxKYeoSKRw6YGl8Zh4H09i4rogLg_IsDsuHz_6y2imQ2ZThGcO50KaNj2uoZtk6MJjhIm-DeHj4UMzC9V43Hky9Dj0pwv06Dn05MGPR4OnQ3s8_MFDqI8EnYdG6RRSH9eHmgryH192ZCKPPyp-52jqHWXHBT-O5D2Rw85F3JtAX7jeqLCYLMfF4seN_MeUC9pzXCKuR0K7o_mC_1DNDPl21NoLSzuO_sSVBEefZ0hrC8mHU0GVtviDH7XzoM7w9CgfTInCDc8DPhPyH0nkw9vgbEfJRJvwC08I98gj6ESu4ylx3FGJfvIKM7ZRsluER8eVIll6hL-EUsoOcz_K4250WM4Rq7qQXFKO9-iNMzSeYxuLL3vB8CnyBsmxX3iOJ9uHUqLgJ0f148ZxD8ka9QjlfHieF3cUCeEPLXWMnHiCMih5_HAbfA5-NKP0I5m2ncijw2mGq0mxLzvOS6idB2dQS0KPJsoNMsyOP5MQHclyXGgmTbiSKPjhD0fsI7lk9ELzD5eUEH0mvGONatyFZ9GK5D8iHs3hvEEXzcSn6egdCc1HIU-gD3mGU71QvsN5nDk-KYXH0EW40kiuLDH-eDgjPDt6NHF4PHjw_Si3w3fhHz9hnhTRJzuuI3wk-At4NLhw6Sgn_KtwccB_iD9gWxUOP8bhHb8HT0evRcJ_ouuC5oM0t0K_I_7gTUpwXI6RZ4fIE-kkynhzvMwFnzmI1MXeQ1xW9MqDHqkj3Fl0fDyeHa2iB9-CF2EuaD9yBWdi4cHjKEoCZzGPfOGhK8tx4kyHSh3SROODkIpRW4eW54J-NEckOZJGPH8S_MXX5HgiHj18MUMWj8UJ_SL-HL0HOxF0_MZ3xDDzoL_QKzr8gOGH8IH-Ii9-eE8s1Bc-7cS1EY3KHPON2D3axMa344eWx4JmH1dKnDxRUtvQ3DJO4spyaH8ORx9yLVlRNcbRH-4T3NERTXrwD4pJKoGvDlt9IeQS9Drcx7jEdHCqHdO2436Ea0cZIlkmBrmOx8WHK0eZC36Kylks47mNI8zEndAcFzleM2hWxkR_PMH14UOYH4V6ovvh4j7eGflx68H24P_gUsHx7fCNx7g2IX5QLpwW5FqWGDyH_vAVrCXgZ0F-iIqOSswe_ESPZqxRH9su6ISvoz2OR0Xt4Olx96CO43gl-CHqB7rxpzjR7EPlctDNQl6SoxJpIT3-wD_q4cmRB1qOPkbeKI3wa9ijBU9E-HSRL9uh4_7wKA1RK1GI5tFxGe0PMQmNf0iPPyIeHf_xJg9O5IeYv3geFuHJID96SRs-HGePG47xRsTFBfpxScthJ1Eq1D9Cwj-eLcZVH-5wwfvRN0b8BzvCPAE5HemWLOgqGfehHc2XNMj7oOxxpOijBDrBMES6ZclxesQzvBX8oD9e9IJ_tJOMagpzNNfBC4-OqTua96i3w6_RK-HR8DmSWULcxMOV43fwP2iuTMi14UwERUrI6MgX5J-S4BbmQ-yPPDn85DhxamIC_7hSPMf9IJmSuAhzYg9OUkrw6UHzoCdyfUjAHf05NGoWB2-InCeS2XFwH4we5ThODp2i7-Dn4BaHMJKSC7qObPKD5ktm1BS-oEyuBc1xXoiThTmSJ5Qx5VGHXmFwcnjjCJ6SIHmi3Mgf4EqHR7uC7xFOZQiZdUOy7MaNn8eHv4EZ6cFH4T_uI_mHvA9OxUEj1phEDTlzHP-D_UmIo3FIhCxRPeiX4wmuJEeeT2hCCslOPNjvBI80EqwUFE3xI9bICXpUBM0zfej0tPglnDeYXIuRH2KP_Ivw5LiUB1nictCdEvfRTTma73hyfNEjrEw-iLMS4-GFPWlCZPmOZuyPOcR_9JUGuyb64_iFL_hkxH6g7YiXF009PLlw7DkO_kHPFE2VrcSToVeQPkR16M3x-DjCE8ePH_mFhD8eocdxXiu6w2nC6ehxIkHe4cwMVlqOvfBTnJi6LNPR7B_4HOm-QE-OPW4i5DiPXM6E39AEH6Vz9MeRb8ePA7kh3ugRUnoERxH6CrVjfHvgx7BPo1aON8UlPEiupIgfBeuNShmoTTz-FCGpHMnNDp9wncF1XDqSPUeYxMf4ZMecHKd-8DrEHz--m3h6_Cr6ozluyRISh9ERH4d7nMcXBhPJB83xDZP-obGET1oRH8nzB2dYNCeO6Ua-7NDx7InwRyuaH6F148qSJ_jT4SyJ8BLRjBnk5EmG3KLQHdtJosyiJsFvoheyZKeQPMqOL0yk4jz847mEX3g61NfxBrXwWChPNGd0fAuq7ALV9EJ6aDx-hPlRH9eO0PrRHNehJzmKXxkhH-oKHz_S47iEzyJyHDr8RyjxFtV4iCoz4kj_glbh4xPyBR8P_UGYUcfDo9_hLwdv-Ee0EZdwCbqOnHjg_IeT4_ng4zDJD8ls5Ds-JniEx1sC58jxaNAp9LqhH2r8oIKe6LiOntByCbEjVnguR9gvXAmPc0HZo7k5_A7yGr9GaNnR49GFZwo0xDkcHj2uHL3RHEfeQbuI-3CP-yGq6cZPdB6xxT3-Ii-OK4Mr1I6D58MnPGJihDyaP9AV4kXIT2i4ZCeeHtWPX3jm4jh7pNJ6_PgiiM-DXMnxwEctxkap7YeDjsmJij6uBOYiJPuR48aPhyeOKb9RUQyeF8n7IecPJsyI8iVQ80RzjshTaHmD8J3w6EDVCk9zXOlxHM1lBX-RI_nRLwf_DP7hB5WOPwgbEeJb4algxgcvvIE14zhO4j0cKYRmLS_6HfxxHf0nzCz0H82DWsiDLxEndO3hP-jxo9-FMId-5A8-EndUBVX06Wj64yqOvN3wFb9DqNKGPjouAulROccfaUPEP8KTQ9cWPD_CHPXmDG9wXUb4Q8uFXA6eG4zawzochcd__INP9C2yHOIR_sLR5wqavHjU8Dji74Tma0jJ4MdF8B2-GH5mGXvhG-GhqPzQjDpygrFz2GGDn4iT69izEY7Q_7ieLZAVEU1Elsi_HB4DL8dk9fiWoelQnkF-KErErMSTNHikqCq0PrgmBeEp-HRU9CHCjIfmIdJTNFUmTQF7VE2EJqm0Is9SFeVyatj4IyQZXDl6NFWWDpeI3DtOY_SLJ8sM9k2QZ2huVMcTA4cAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARSABkmFECASIARQAAIBggQBDggASECKMVIgJIwwQQUAKChDAQAQMJEcwRIAQQAAlCBGEOCEEMA0A5IARBSAgCiUMCMQEEcdYoYQUglgpgCDDCAMoJIAIIxBRyEggCFAIECGEYQYQp4oBgCCAICSAKEUUMIgwIRAxQwDEEDCCOCsAEYIQBIpBUhhoFlGQcAUYgBAQAJIAhgAglFFEYGAGkEswIAAxSlEBAhABAGKWQktApAQRQBABigBIBAAMyNAQqpYACBgACBAHEOAMIEtIoAAgThBkCCCHIChMYAQYBYAUAgCAmTEgEEAEEUUIhNRAABgChCACCKAAEAAAQYwghCAAAAEJgMMEYCEhAAiADCAAFRAACOUKII4gBowwwECABgAJAIKgMoogJAwABQiFBODLECMSQAQYoYCRAAABgjBBGEUiAYQAR6ghiAhBKCFMGEeAFEIIAYBBDABEhFDKKIgOYoAQo4QgToElEAPIMIIAQtVZQgxQoBJIKAENGESSIFAQwgBAgADAAAMBEOGKIQMpJAAgQRCljKCGICKQAIQAYYwQXQCCgDBJECWIIGAgwxgRQRAnDhMMOGICMEAgYIYEiAhADCBGEMiMIAsQQoBAiBAgPiHBEGiMMIIoSoJAABCFJDAFEaKAIAIYyQJQBgigCBAMAgGIAQQYRIZBASAhDABEIIgLEEQA4JgCBSgAAnAEKIIYJoIAYAjAkQCAiCAEMIACYAYAIFDxxSgElGGAcEaGMkIQBBDlSEDFBFRKLAOEEJMIQBYgQgEAGAGEEEKIIcYAZIRChSDOLiAXMMGohUk4IYJFQCAkECCGWGCCIMMwAABATlCgghCjMGWCSEMIAAAigwjhjCAMICQCIEAIZA4gwTgACkGKMMEIVUEwABBzAmBnBlBKCSGIMAcAqpagFBUWCgBRIGCuYUYQhwAggggEIjjKKAyAAMwoE5owIziIiBCSGCAIMAEAoggxFCCAmmFTEWMKUYQgNQBhBgCAEjFNIKeOMQ4AwRYBBwAjGgDDAMQSMUUwAIqAR1jpIEEEEKGMEAkYIhBADQgBEqUFAFEqQIYI4JhSwwihRjUCAGAeQAYgAYrRhgBGkjEBACCEBAEYopIAwQCCGBDAAGUAAoooJJKByRkBDiJDCMa2UAQMYYRgQAGBFADBIGKEAYg4AgAgQSgAoHCFMCgCUAEY5BQBCxjMIEBBEEgAA"); - } - - [Test] - public void should_parse_fpcalc_text_with_noninteger_duration() - { - var text = @"FILE=Adele - 01 - 21 - Rolling in the Deep.flac -DURATION=229.29 -FINGERPRINT=AQAHJlMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-IehuDm92Q9xDzISyH67jOoc_R_OijI61TJLuObzn-zWi6S2gVT3jUIkhOw2pMgU13XPuGM4c7_B_yHCcPPYpD4Tp6DW6To89xIS-qH31w6vjBLksu4mFEDcndIByvI9SPS4PODM2PdumCfOKDXJByhPGKy8FFZcP3olGs4z5T1MrC4yHiK8e_QdSD-KBz9M3RjNIRPfFQQxxH_PBxKYeoSKRw6YGl8Zh4H09i4rogLg_IsDsuHz_6y2imQ2ZThGcO50KaNj2uoZtk6MJjhIm-DeHj4UMzC9V43Hky9Dj0pwv06Dn05MGPR4OnQ3s8_MFDqI8EnYdG6RRSH9eHmgryH192ZCKPPyp-52jqHWXHBT-O5D2Rw85F3JtAX7jeqLCYLMfF4seN_MeUC9pzXCKuR0K7o_mC_1DNDPl21NoLSzuO_sSVBEefZ0hrC8mHU0GVtviDH7XzoM7w9CgfTInCDc8DPhPyH0nkw9vgbEfJRJvwC08I98gj6ESu4ylx3FGJfvIKM7ZRsluER8eVIll6hL-EUsoOcz_K4250WM4Rq7qQXFKO9-iNMzSeYxuLL3vB8CnyBsmxX3iOJ9uHUqLgJ0f148ZxD8ka9QjlfHieF3cUCeEPLXWMnHiCMih5_HAbfA5-NKP0I5m2ncijw2mGq0mxLzvOS6idB2dQS0KPJsoNMsyOP5MQHclyXGgmTbiSKPjhD0fsI7lk9ELzD5eUEH0mvGONatyFZ9GK5D8iHs3hvEEXzcSn6egdCc1HIU-gD3mGU71QvsN5nDk-KYXH0EW40kiuLDH-eDgjPDt6NHF4PHjw_Si3w3fhHz9hnhTRJzuuI3wk-At4NLhw6Sgn_KtwccB_iD9gWxUOP8bhHb8HT0evRcJ_ouuC5oM0t0K_I_7gTUpwXI6RZ4fIE-kkynhzvMwFnzmI1MXeQ1xW9MqDHqkj3Fl0fDyeHa2iB9-CF2EuaD9yBWdi4cHjKEoCZzGPfOGhK8tx4kyHSh3SROODkIpRW4eW54J-NEckOZJGPH8S_MXX5HgiHj18MUMWj8UJ_SL-HL0HOxF0_MZ3xDDzoL_QKzr8gOGH8IH-Ii9-eE8s1Bc-7cS1EY3KHPON2D3axMa344eWx4JmH1dKnDxRUtvQ3DJO4spyaH8ORx9yLVlRNcbRH-4T3NERTXrwD4pJKoGvDlt9IeQS9Drcx7jEdHCqHdO2436Ea0cZIlkmBrmOx8WHK0eZC36Kylks47mNI8zEndAcFzleM2hWxkR_PMH14UOYH4V6ovvh4j7eGflx68H24P_gUsHx7fCNx7g2IX5QLpwW5FqWGDyH_vAVrCXgZ0F-iIqOSswe_ESPZqxRH9su6ISvoz2OR0Xt4Olx96CO43gl-CHqB7rxpzjR7EPlctDNQl6SoxJpIT3-wD_q4cmRB1qOPkbeKI3wa9ijBU9E-HSRL9uh4_7wKA1RK1GI5tFxGe0PMQmNf0iPPyIeHf_xJg9O5IeYv3geFuHJID96SRs-HGePG47xRsTFBfpxScthJ1Eq1D9Cwj-eLcZVH-5wwfvRN0b8BzvCPAE5HemWLOgqGfehHc2XNMj7oOxxpOijBDrBMES6ZclxesQzvBX8oD9e9IJ_tJOMagpzNNfBC4-OqTua96i3w6_RK-HR8DmSWULcxMOV43fwP2iuTMi14UwERUrI6MgX5J-S4BbmQ-yPPDn85DhxamIC_7hSPMf9IJmSuAhzYg9OUkrw6UHzoCdyfUjAHf05NGoWB2-InCeS2XFwH4we5ThODp2i7-Dn4BaHMJKSC7qObPKD5ktm1BS-oEyuBc1xXoiThTmSJ5Qx5VGHXmFwcnjjCJ6SIHmi3Mgf4EqHR7uC7xFOZQiZdUOy7MaNn8eHv4EZ6cFH4T_uI_mHvA9OxUEj1phEDTlzHP-D_UmIo3FIhCxRPeiX4wmuJEeeT2hCCslOPNjvBI80EqwUFE3xI9bICXpUBM0zfej0tPglnDeYXIuRH2KP_Ivw5LiUB1nictCdEvfRTTma73hyfNEjrEw-iLMS4-GFPWlCZPmOZuyPOcR_9JUGuyb64_iFL_hkxH6g7YiXF009PLlw7DkO_kHPFE2VrcSToVeQPkR16M3x-DjCE8ePH_mFhD8eocdxXiu6w2nC6ehxIkHe4cwMVlqOvfBTnJi6LNPR7B_4HOm-QE-OPW4i5DiPXM6E39AEH6Vz9MeRb8ePA7kh3ugRUnoERxH6CrVjfHvgx7BPo1aON8UlPEiupIgfBeuNShmoTTz-FCGpHMnNDp9wncF1XDqSPUeYxMf4ZMecHKd-8DrEHz--m3h6_Cr6ozluyRISh9ERH4d7nMcXBhPJB83xDZP-obGET1oRH8nzB2dYNCeO6Ua-7NDx7InwRyuaH6F148qSJ_jT4SyJ8BLRjBnk5EmG3KLQHdtJosyiJsFvoheyZKeQPMqOL0yk4jz847mEX3g61NfxBrXwWChPNGd0fAuq7ALV9EJ6aDx-hPlRH9eO0PrRHNehJzmKXxkhH-oKHz_S47iEzyJyHDr8RyjxFtV4iCoz4kj_glbh4xPyBR8P_UGYUcfDo9_hLwdv-Ee0EZdwCbqOnHjg_IeT4_ng4zDJD8ls5Ds-JniEx1sC58jxaNAp9LqhH2r8oIKe6LiOntByCbEjVnguR9gvXAmPc0HZo7k5_A7yGr9GaNnR49GFZwo0xDkcHj2uHL3RHEfeQbuI-3CP-yGq6cZPdB6xxT3-Ii-OK4Mr1I6D58MnPGJihDyaP9AV4kXIT2i4ZCeeHtWPX3jm4jh7pNJ6_PgiiM-DXMnxwEctxkap7YeDjsmJij6uBOYiJPuR48aPhyeOKb9RUQyeF8n7IecPJsyI8iVQ80RzjshTaHmD8J3w6EDVCk9zXOlxHM1lBX-RI_nRLwf_DP7hB5WOPwgbEeJb4algxgcvvIE14zhO4j0cKYRmLS_6HfxxHf0nzCz0H82DWsiDLxEndO3hP-jxo9-FMId-5A8-EndUBVX06Wj64yqOvN3wFb9DqNKGPjouAulROccfaUPEP8KTQ9cWPD_CHPXmDG9wXUb4Q8uFXA6eG4zawzochcd__INP9C2yHOIR_sLR5wqavHjU8Dji74Tma0jJ4MdF8B2-GH5mGXvhG-GhqPzQjDpygrFz2GGDn4iT69izEY7Q_7ieLZAVEU1Elsi_HB4DL8dk9fiWoelQnkF-KErErMSTNHikqCq0PrgmBeEp-HRU9CHCjIfmIdJTNFUmTQF7VE2EJqm0Is9SFeVyatj4IyQZXDl6NFWWDpeI3DtOY_SLJ8sM9k2QZ2huVMcTA4cAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARSABkmFECASIARQAAIBggQBDggASECKMVIgJIwwQQUAKChDAQAQMJEcwRIAQQAAlCBGEOCEEMA0A5IARBSAgCiUMCMQEEcdYoYQUglgpgCDDCAMoJIAIIxBRyEggCFAIECGEYQYQp4oBgCCAICSAKEUUMIgwIRAxQwDEEDCCOCsAEYIQBIpBUhhoFlGQcAUYgBAQAJIAhgAglFFEYGAGkEswIAAxSlEBAhABAGKWQktApAQRQBABigBIBAAMyNAQqpYACBgACBAHEOAMIEtIoAAgThBkCCCHIChMYAQYBYAUAgCAmTEgEEAEEUUIhNRAABgChCACCKAAEAAAQYwghCAAAAEJgMMEYCEhAAiADCAAFRAACOUKII4gBowwwECABgAJAIKgMoogJAwABQiFBODLECMSQAQYoYCRAAABgjBBGEUiAYQAR6ghiAhBKCFMGEeAFEIIAYBBDABEhFDKKIgOYoAQo4QgToElEAPIMIIAQtVZQgxQoBJIKAENGESSIFAQwgBAgADAAAMBEOGKIQMpJAAgQRCljKCGICKQAIQAYYwQXQCCgDBJECWIIGAgwxgRQRAnDhMMOGICMEAgYIYEiAhADCBGEMiMIAsQQoBAiBAgPiHBEGiMMIIoSoJAABCFJDAFEaKAIAIYyQJQBgigCBAMAgGIAQQYRIZBASAhDABEIIgLEEQA4JgCBSgAAnAEKIIYJoIAYAjAkQCAiCAEMIACYAYAIFDxxSgElGGAcEaGMkIQBBDlSEDFBFRKLAOEEJMIQBYgQgEAGAGEEEKIIcYAZIRChSDOLiAXMMGohUk4IYJFQCAkECCGWGCCIMMwAABATlCgghCjMGWCSEMIAAAigwjhjCAMICQCIEAIZA4gwTgACkGKMMEIVUEwABBzAmBnBlBKCSGIMAcAqpagFBUWCgBRIGCuYUYQhwAggggEIjjKKAyAAMwoE5owIziIiBCSGCAIMAEAoggxFCCAmmFTEWMKUYQgNQBhBgCAEjFNIKeOMQ4AwRYBBwAjGgDDAMQSMUUwAIqAR1jpIEEEEKGMEAkYIhBADQgBEqUFAFEqQIYI4JhSwwihRjUCAGAeQAYgAYrRhgBGkjEBACCEBAEYopIAwQCCGBDAAGUAAoooJJKByRkBDiJDCMa2UAQMYYRgQAGBFADBIGKEAYg4AgAgQSgAoHCFMCgCUAEY5BQBCxjMIEBBEEgAA -"; - - var result = Subject.ParseFpcalcTextOutput(text); - result.Duration.Should().Be(229.29); - result.Fingerprint.Should().Be("AQAHJlMURlEURcgP6cwRD43Y4Ptw9FowncWPWkf6GB9-JYdP9OgJHw8u4Apw4SsOHMdxHAfwHIfYET_0HiZ55MfxNCm8Hj-mRM8KLlXwIzqS-Que_Cg7NEseE_2j4DUjJBOvI08UNNUufEd5NM-OHzmSUZsO58er7nhUeN6EK3HYwhe0H-fxXEFzlOSHJwpj3MevID7kHyqVqBH6zEI6GzmSs4HTDz4j9DjxKHDvpLiOH7l4iFUWRXiiqtCJmMqNPmiAZEyY5AgTLclxmSWuwJ-O33jz4KdwHt-PsDHRjBNyCQ_-KcGPhoePsJNyiJOiI-5VPKMj_McvfNQRUkyiImEzAv2Ckxb-RUJ-CVpGhMYnB5em4scvHFeuoU7DwHugT8fRecPVpMF5_Cb8jNvw4n_wJ6iV4xcSHuFxKcfTBhVF5uiPA6OSoWQP5x_6BX-5YDoaJT_OLA3e0Ifr4D2SH2EYB-WShLiE6plg5U2G6jlOSgy-G8-Rk0XD7yiP4DyPfcejiQ2aH9WVHKeOJ5eQP9CeKEfD44zw45kj_NAQJmIWfMTPCJF048IPPTtcB_GP_2ieFydyxYXGvUgffIO1D96SHW10vEeYI9mNR-qLhnpwfYHz49KR8ijnol58pDGLKWuF4wvKTUGjrE-Q79COdFyI8Aze4C70LMP24-YKJLtSeCHqajJ6e2g0qsdzBd94RNdxHY80oomYocdB5hNiUrGIVtrhJ0f4CY-Y48yOF5rFI93sgNF2hNRhTSk65odGaUhJClc5ArOGdi8-oz_SzaqQ3MKV63DkGX8NT07wVcdf5MmO5Av8C9dOONGIS_mRS7gO8fjhLNMFbQqq4zF0jRPir2j2Y9_xH5Z-_EFiHWE-oaePh8JN3CsaiYgkGvrR_OgVaI2iHv_gTLsQaTeuZ8K5HUdMCWUlHpLIIFyO8TiNO2nQOHzwLkfYQg2RHxXlUfDxHX-MO9Pxwc8J90JSEzmDJk-Ji0cpZanw44mOWpKEkkHDsUFkZsfNaJCOqDvK_fg-9NHx5UHtFGEOPUeu47hw4dzwH22Nc9pgK8dZhJ-h8wipwyS8Dw8cZ0evC8kZJcgrHT22jsfhH_QCv4jMHNp25NLx6Hh4tEtaePzgcNHxDOkYQ3tCxBsvPFKOfyzCB-L5IHyCpzhFHo9zvMeP5vrQbdzwK8N_hFG6F0mdo2GOJ4yxM0bJRFaGH3WyHUdzHWWe4uoH8hWS8EGOGuUSBZ-E6w7sZsKpIId-IzyDptLxhD76GpfxNDHSkdCTS0JMFS-8Rh6e48c6Hv2O8CG05MinRcUX9A0cKoSv4Ts8KbSQbCXyDDeDZ_mKUrwHP8tRi8d94UcX3ImMLzq8o3-DnFXwHG2UJ_Au6FlwNLgOXU_xakKv4zp8VMeN_vBz9OCbQzsFP7h8PB96Df8llNJSWI8KfVkqZMcPaw5ePEgf6HKQjj2YTRmOxslyTJ-K_kj3Qj9M6TjCM33QixGcX8PzHNfxDOfhMx2SHflz_Dr-K6hSKVLQ7MSjII-UQ9fQ53Bi6ahMoz5jNA304xDz7RjTI08eXKeChzmeDeUJfw7OEPVGnB_yoz_M6sZj8MOfHE5wXKLhT0V-MMhjlDv0C-mP_jgt4cxRMgoLSz5GkUZ-3MFTPHCpB-W2EheX43iWeUgfDhdJPAsR_oKWmDGeJRMRoyea3fhyVA6RjsuCCxdDiD-2fsizC5eSp_CPh4UnP5gU6sOpL7g3ocyCSDn0I7-L4znKBg3uKDmeW8Nzsriqg5eMHk33Cn9Q_0hPQtMX4oqOfMedHI-IehuDm92Q9xDzISyH67jOoc_R_OijI61TJLuObzn-zWi6S2gVT3jUIkhOw2pMgU13XPuGM4c7_B_yHCcPPYpD4Tp6DW6To89xIS-qH31w6vjBLksu4mFEDcndIByvI9SPS4PODM2PdumCfOKDXJByhPGKy8FFZcP3olGs4z5T1MrC4yHiK8e_QdSD-KBz9M3RjNIRPfFQQxxH_PBxKYeoSKRw6YGl8Zh4H09i4rogLg_IsDsuHz_6y2imQ2ZThGcO50KaNj2uoZtk6MJjhIm-DeHj4UMzC9V43Hky9Dj0pwv06Dn05MGPR4OnQ3s8_MFDqI8EnYdG6RRSH9eHmgryH192ZCKPPyp-52jqHWXHBT-O5D2Rw85F3JtAX7jeqLCYLMfF4seN_MeUC9pzXCKuR0K7o_mC_1DNDPl21NoLSzuO_sSVBEefZ0hrC8mHU0GVtviDH7XzoM7w9CgfTInCDc8DPhPyH0nkw9vgbEfJRJvwC08I98gj6ESu4ylx3FGJfvIKM7ZRsluER8eVIll6hL-EUsoOcz_K4250WM4Rq7qQXFKO9-iNMzSeYxuLL3vB8CnyBsmxX3iOJ9uHUqLgJ0f148ZxD8ka9QjlfHieF3cUCeEPLXWMnHiCMih5_HAbfA5-NKP0I5m2ncijw2mGq0mxLzvOS6idB2dQS0KPJsoNMsyOP5MQHclyXGgmTbiSKPjhD0fsI7lk9ELzD5eUEH0mvGONatyFZ9GK5D8iHs3hvEEXzcSn6egdCc1HIU-gD3mGU71QvsN5nDk-KYXH0EW40kiuLDH-eDgjPDt6NHF4PHjw_Si3w3fhHz9hnhTRJzuuI3wk-At4NLhw6Sgn_KtwccB_iD9gWxUOP8bhHb8HT0evRcJ_ouuC5oM0t0K_I_7gTUpwXI6RZ4fIE-kkynhzvMwFnzmI1MXeQ1xW9MqDHqkj3Fl0fDyeHa2iB9-CF2EuaD9yBWdi4cHjKEoCZzGPfOGhK8tx4kyHSh3SROODkIpRW4eW54J-NEckOZJGPH8S_MXX5HgiHj18MUMWj8UJ_SL-HL0HOxF0_MZ3xDDzoL_QKzr8gOGH8IH-Ii9-eE8s1Bc-7cS1EY3KHPON2D3axMa344eWx4JmH1dKnDxRUtvQ3DJO4spyaH8ORx9yLVlRNcbRH-4T3NERTXrwD4pJKoGvDlt9IeQS9Drcx7jEdHCqHdO2436Ea0cZIlkmBrmOx8WHK0eZC36Kylks47mNI8zEndAcFzleM2hWxkR_PMH14UOYH4V6ovvh4j7eGflx68H24P_gUsHx7fCNx7g2IX5QLpwW5FqWGDyH_vAVrCXgZ0F-iIqOSswe_ESPZqxRH9su6ISvoz2OR0Xt4Olx96CO43gl-CHqB7rxpzjR7EPlctDNQl6SoxJpIT3-wD_q4cmRB1qOPkbeKI3wa9ijBU9E-HSRL9uh4_7wKA1RK1GI5tFxGe0PMQmNf0iPPyIeHf_xJg9O5IeYv3geFuHJID96SRs-HGePG47xRsTFBfpxScthJ1Eq1D9Cwj-eLcZVH-5wwfvRN0b8BzvCPAE5HemWLOgqGfehHc2XNMj7oOxxpOijBDrBMES6ZclxesQzvBX8oD9e9IJ_tJOMagpzNNfBC4-OqTua96i3w6_RK-HR8DmSWULcxMOV43fwP2iuTMi14UwERUrI6MgX5J-S4BbmQ-yPPDn85DhxamIC_7hSPMf9IJmSuAhzYg9OUkrw6UHzoCdyfUjAHf05NGoWB2-InCeS2XFwH4we5ThODp2i7-Dn4BaHMJKSC7qObPKD5ktm1BS-oEyuBc1xXoiThTmSJ5Qx5VGHXmFwcnjjCJ6SIHmi3Mgf4EqHR7uC7xFOZQiZdUOy7MaNn8eHv4EZ6cFH4T_uI_mHvA9OxUEj1phEDTlzHP-D_UmIo3FIhCxRPeiX4wmuJEeeT2hCCslOPNjvBI80EqwUFE3xI9bICXpUBM0zfej0tPglnDeYXIuRH2KP_Ivw5LiUB1nictCdEvfRTTma73hyfNEjrEw-iLMS4-GFPWlCZPmOZuyPOcR_9JUGuyb64_iFL_hkxH6g7YiXF009PLlw7DkO_kHPFE2VrcSToVeQPkR16M3x-DjCE8ePH_mFhD8eocdxXiu6w2nC6ehxIkHe4cwMVlqOvfBTnJi6LNPR7B_4HOm-QE-OPW4i5DiPXM6E39AEH6Vz9MeRb8ePA7kh3ugRUnoERxH6CrVjfHvgx7BPo1aON8UlPEiupIgfBeuNShmoTTz-FCGpHMnNDp9wncF1XDqSPUeYxMf4ZMecHKd-8DrEHz--m3h6_Cr6ozluyRISh9ERH4d7nMcXBhPJB83xDZP-obGET1oRH8nzB2dYNCeO6Ua-7NDx7InwRyuaH6F148qSJ_jT4SyJ8BLRjBnk5EmG3KLQHdtJosyiJsFvoheyZKeQPMqOL0yk4jz847mEX3g61NfxBrXwWChPNGd0fAuq7ALV9EJ6aDx-hPlRH9eO0PrRHNehJzmKXxkhH-oKHz_S47iEzyJyHDr8RyjxFtV4iCoz4kj_glbh4xPyBR8P_UGYUcfDo9_hLwdv-Ee0EZdwCbqOnHjg_IeT4_ng4zDJD8ls5Ds-JniEx1sC58jxaNAp9LqhH2r8oIKe6LiOntByCbEjVnguR9gvXAmPc0HZo7k5_A7yGr9GaNnR49GFZwo0xDkcHj2uHL3RHEfeQbuI-3CP-yGq6cZPdB6xxT3-Ii-OK4Mr1I6D58MnPGJihDyaP9AV4kXIT2i4ZCeeHtWPX3jm4jh7pNJ6_PgiiM-DXMnxwEctxkap7YeDjsmJij6uBOYiJPuR48aPhyeOKb9RUQyeF8n7IecPJsyI8iVQ80RzjshTaHmD8J3w6EDVCk9zXOlxHM1lBX-RI_nRLwf_DP7hB5WOPwgbEeJb4algxgcvvIE14zhO4j0cKYRmLS_6HfxxHf0nzCz0H82DWsiDLxEndO3hP-jxo9-FMId-5A8-EndUBVX06Wj64yqOvN3wFb9DqNKGPjouAulROccfaUPEP8KTQ9cWPD_CHPXmDG9wXUb4Q8uFXA6eG4zawzochcd__INP9C2yHOIR_sLR5wqavHjU8Dji74Tma0jJ4MdF8B2-GH5mGXvhG-GhqPzQjDpygrFz2GGDn4iT69izEY7Q_7ieLZAVEU1Elsi_HB4DL8dk9fiWoelQnkF-KErErMSTNHikqCq0PrgmBeEp-HRU9CHCjIfmIdJTNFUmTQF7VE2EJqm0Is9SFeVyatj4IyQZXDl6NFWWDpeI3DtOY_SLJ8sM9k2QZ2huVMcTA4cAAYgB4YwSDACBiFBMPPGctY6a6pAAxighhEjKAAaBNsgIIAAQRgFFHCBGIACQIBJAoAAADCKiCDLSCCABQYQQwIwEigkArKGII0OUQEwAogBRoCCHCCKQAEcEkQYQYoQSigDjCBMCIUCJIUQJQQRRiDAAHSEKEOCCEAAgDRQBxDEgkBEGEAQQFkIIIAQhAgnBAFTAQIEAQYgxYwBClAkEACMEAEAAMQgISAxCgiiCACESIWQAUWYQBoBDBhBGgBBAMSMkYogAIwjwBCMkACLCCASEIMARg4QCBCAijCYAKweEAkAJYRgSAkDjjBCMQgioMIYBQIgDQhkBGiKEQAeBFAQAZoACBgFKFAEAOQMAEIQYgICShChGCCDKESSYoEIQAIRiFkAAgQJMCWMYRUAIgAQAigFEgFDEEAEwEAYQaQw0BgEHADDWGSCAWEgIBQQxBghmjBQCCEqMA0YpQIwAwgDjHFBECiWUEQYxohABRAhAjAUCESUARgRQYgAARggKMAVOAEIEc4gyJ4ABABCCjGMIKAIAEQIAIAwChAEgAGEAGAeIUMZY4QghSBhADSCCGiKNlAQoogAChjCDEAEEWEIRA0QohoQAQCkECEGQEQIEMUwYgIgBABgECECCKEQAAkIgYZARSABkmFECASIARQAAIBggQBDggASECKMVIgJIwwQQUAKChDAQAQMJEcwRIAQQAAlCBGEOCEEMA0A5IARBSAgCiUMCMQEEcdYoYQUglgpgCDDCAMoJIAIIxBRyEggCFAIECGEYQYQp4oBgCCAICSAKEUUMIgwIRAxQwDEEDCCOCsAEYIQBIpBUhhoFlGQcAUYgBAQAJIAhgAglFFEYGAGkEswIAAxSlEBAhABAGKWQktApAQRQBABigBIBAAMyNAQqpYACBgACBAHEOAMIEtIoAAgThBkCCCHIChMYAQYBYAUAgCAmTEgEEAEEUUIhNRAABgChCACCKAAEAAAQYwghCAAAAEJgMMEYCEhAAiADCAAFRAACOUKII4gBowwwECABgAJAIKgMoogJAwABQiFBODLECMSQAQYoYCRAAABgjBBGEUiAYQAR6ghiAhBKCFMGEeAFEIIAYBBDABEhFDKKIgOYoAQo4QgToElEAPIMIIAQtVZQgxQoBJIKAENGESSIFAQwgBAgADAAAMBEOGKIQMpJAAgQRCljKCGICKQAIQAYYwQXQCCgDBJECWIIGAgwxgRQRAnDhMMOGICMEAgYIYEiAhADCBGEMiMIAsQQoBAiBAgPiHBEGiMMIIoSoJAABCFJDAFEaKAIAIYyQJQBgigCBAMAgGIAQQYRIZBASAhDABEIIgLEEQA4JgCBSgAAnAEKIIYJoIAYAjAkQCAiCAEMIACYAYAIFDxxSgElGGAcEaGMkIQBBDlSEDFBFRKLAOEEJMIQBYgQgEAGAGEEEKIIcYAZIRChSDOLiAXMMGohUk4IYJFQCAkECCGWGCCIMMwAABATlCgghCjMGWCSEMIAAAigwjhjCAMICQCIEAIZA4gwTgACkGKMMEIVUEwABBzAmBnBlBKCSGIMAcAqpagFBUWCgBRIGCuYUYQhwAggggEIjjKKAyAAMwoE5owIziIiBCSGCAIMAEAoggxFCCAmmFTEWMKUYQgNQBhBgCAEjFNIKeOMQ4AwRYBBwAjGgDDAMQSMUUwAIqAR1jpIEEEEKGMEAkYIhBADQgBEqUFAFEqQIYI4JhSwwihRjUCAGAeQAYgAYrRhgBGkjEBACCEBAEYopIAwQCCGBDAAGUAAoooJJKByRkBDiJDCMa2UAQMYYRgQAGBFADBIGKEAYg4AgAgQSgAoHCFMCgCUAEY5BQBCxjMIEBBEEgAA"); - } - - [TestCase("nin.mp3")] - [TestCase("nin.flac")] - public void should_fingerprint_file(string file) - { - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", file); - - var fingerprint = Subject.GetFingerprint(path); - fingerprint.Should().NotBeNull(); - fingerprint.Fingerprint.Should().BeOneOf( - "AQACmomSJEySRNISHCa6zDh6OO_hoUfr48cvHD83-JApYL6F8oCMHvlg46qOHYf740L6ascN_fj0wh90aD2OC41FC-Exf0IvPBKyH6qNOGLEgrBxXC3w4MiFB2J--Cce4cYXpLwGXER64RHxQxT142eJFMeL40g_HSbUh7h6xONhuDZ-5NpxFrpwfCrSo4pj_EJYHoehvzjeHcbnDGoOH30WPEYeEz3xI72P0sLRNRHx49IB_IXx4_iH5yF-HOdx2FoE8R5-HM2hJmOF6hFSXziPHdtxmLmQ5sKYHzouFjlMokfOBncsaE91mPoQ_MctTCqRX9CEnziO_zhcCPk_POmOoz8u1KOQ6-ihazgaHw9OaPlxAvmKfDhUpcWH_MNbBr-Do0eYH7p-5PqFPUbD5TK2o6p0_MeP8IcOw0c-H8eRZxCjRniE8HgPhlKKxqmk4jnai8JZBO9SPMauFEeOHxeOFj_-NsgFdaHxIzx8PMzQRsQfRL4GHvoiNLnwXD6uA-Jx_DiM4-Wh5nBUIXx8vEMtBt60wWwQ3mh7ovE1PCmaHMdx9AiOM8SFXMfVC_oToDl64sqSsfiNB-Wh5_iT4xf-D8dh6PjxAP6CP8fjQf9ghM069IYfwxf8C5cQdwcXC5-CPNiP48WBKh_i49DN4Dz6C82Rx8mQH7-wgzls5VDznPhz4PBx_AAr-PjxVBHUB-aHQld2oWfQODnOoKcLX7iW4fHBFcfxHPOgH_Mt_HjEJDoq9cKH44nyQyfCjBeeVBP4VEUfvIvwIIueUYWTJviFH_lx_EeOQ7wG1sibwNGL7oh_6GzQTGKIkFm64CE-1TiYH_6OWHXw_Dh-2Dp0_TgR43mOXjOOkOGhZdKHPHiIvgy2H_0xJlsQX9Cu48gN__iR5_jBHj7U6wiVtyj9oemOz8LR_Ba-IM8VXDPCJ1PBRdMRyhe8aYZ-HP3R48fBvdCeHM9R7Qve48htuMoS0eiR-_jxoDkYLjoeJ9DUU_iA4zr44zec4_EOPcdTeAib4URPPLCPnseniUL0D6HSHf9xoz3wByF73Ic-VA_-fYh_ePwQ_cGlQD-ap-jDHOEpXENWwrEyPMe1I8ePHz_yQz-8D_-NrIbzo7uF-IcuohkZXBpyH89jnAJFHSH5DP9R5fh0FDrB42mGazj-bbhz6DwahGSKq_jxGwx3-EIsbnh-wdYO4YSPHz8OQszxPMSPhsf3HDl6zTCRhwr6g1fxPAej44txfLhw6JiPisfb4LhzlDy0ZDhj5NqIo3-w_UA6Cn2GKk6hHtcAH7-JH4cDNSkeHS9yH9_x4cyQ6yIemM5xBefx9HCqGT-OHzxOaDwefLfwpBfyC-EP_9CZo88snEPOHl-EHn4QMSd-XAN2PAe8HdBlH9SLrzm6HH-hK0d5mCrOoj9-MMe3hrhycPERjw9-YciJHx-EP8cTsRvOw5OOHjpjY14yEj0ycbBxZUXEVHB25BrM4McOhCwwCCDgjAQAFIOoAIICIQSAQiBDFELAEaYUMMtAKgUSACBnRJEQEGCAeAoRRIQQliFAsVYGGOKIcEYAAIVRgjgAJDNGKYCUBgIIKLwxCBHjCVDGECYuAsJBDhUSBhGhCACGKKOEEUUI4AAxHAkFHQEAQWeQJAYIYGQUAgBBgNGAMAEQMABRJwQSD2gCGAIMAOUIYhQBKwBjBCKmlCIBAACUYmYJZA0gRDgBCDDwWQcRAAAARJxACoFuBABOAACIwlY5Q4BwQAEAJDDYKZGQwogIyQwSABFmFDHDCAKAUMwooYAQABEgACPEAEORcQQ4aAAgHBRBpFFMECUoUJQZs4ARSBEFgUHKOUGAAYQ5QxAQyAFADDlAKgKMUAIQBxpQjBDLIBNCAGKsIBQRRQSSwjkFkCPDEOEQIUwKJJiywADhtHGAEaKAUBASxRRBxBgCDFBAKYWAAkIAYQQQBAkLBFEAKEIexEYxQYhFBghiAEDECCABMQAACh1QiBAgCDBUIEUZQAAAwpxYADFzAIAEIQEwkAQIAJhwylElhINSOMEEAwwggJVSAjHjgBQIEcMQcUARBJRT8AKBgAMAGKMIABIxQYVwhACAFbKAAUEAccAR4wmRlAjCiEEGMGIcEAQYZCSCTCInBQ", - "AQACmomSJEySRNISHCa6zDh6iHkPcejR-vjxC8fPDT5kCphvoTwgo0c-2LiqY8fh_riQvtpxQz8-vfAHHVqP40Jj0UJ4zJ_QC4-E7IdqI44YsSBsHFcLPDhy4YGYH_6JR7jxBSmvAReRXnhE_BBF_fhZIsXx4jjST4cJ9SGuHvF4GK6NH7l2nIUuHJ-K9KjiGL8Qlsdh6C-Od4fxOYOaw0efBY-Rx0RP_Ejvo7RwdE1E_Lh0AH9h_Dj-4XmIH8d5HLYWQbyHH0dzqMlYoXqE1BfOY8d2HGYupLkw5oeOi0UOk-iRs8EdC9pTHaY-BP9xC5NK5Bc04SeO4z8OF0L-D0-64-iPC_Uo5Dp66BqOxseDE1p-nEC-Ih8OVWnxIf_wlsHv4OgR5oeuH7l-YY_RcLmM7agqHf_xI_yhw_CRz8dx5BnEqBEeITzeg6GUonEqqXiO9qJwFsG7FI-xK8WR48eFo8WPvw1yQV1o_AgPHw8ztBHxB5GvgYe-CE0uPJeP64B4HD8O43h5qDkcVQgfH-9Qi4E3bTAbhDfanmh8DU-KJsdxHD2C4wxxIddx9YL-BGiOnriyZCx-40F56Dn-5PiF_8NxGDp-PIC_4M_xeNA_GGGzDr3hx_AF_8IlxN3BxcKnIA_243hxoMqH-Dh0MziP_kJz5HEy5Mcv7GAOWznUPCf-HDh8HD_ACj5-PFUE9YH5odCVXegZNE6OM-jpwheuZXh8cMVxPMc86Md8Cz8eMYmOSr3w4Xii_NCJMOOFJ9UEPlXRB-8iPMiiZ1ThpAl-4Ud-HP-R4xCvgTXyJnD0ojviHzobNJMYImSWLniITzUO5oe_I1YdPD-OH7YOXT9OxHieo9eMI2R4aJn0IQ8eoi-D7Ud_jMkWxBe06zhywz9-5Dl-sIcP9TpC5S1Kf2i647NwNL-FL8hzBdeM8MlUcNF0hPIFb5qhH0d_9PhxcC-0J8dzVPuC9zhyG66yRDR65D5-PGgOhouOxwk09RQ-4LgO_vgN53i8Q8_xFB7CZjjREw_so-fxaaIQ_UOodMd_3GgP_EHIHvehD9WDfx_iHx4_RH9wKdCP5in6MEd4CteQlXCsDM9x7cjx48eP_NAP78N_I6vh_OhuIf6hi2hGBpeG3MfzGKdAUUdIPsN_VDk-HYVO8Hia4RqOfxvuHDqPBiGZ4ip-_AbDHb4QixueX7C1Qzjh48ePgxBzPA_xo-HxPUeOXjNM5KGC_uBVPM_B6PhiHB8uHDrmo-LxNjjuHCUPLRnOGLk24ugfbD-QjkKfoYpTqMc1wMdv4sfhQE2KR8eL3Md3fDgz5LqIB6ZzXMF5PD2casaP4wePExqPB98tPOmF_EL4wz905ugzC-eQs8cXoYcfRMyJH9eAHc8Bbwd02Qf14muOLsdf6MpRHqaKs-iPH8zxrSGuHFx8xOODXxhy4scH4c_xROyG8_Cko4fO2JiXjESPTBxsXFkRMRWcHbkGM_ixA4QsMAgg4IwEABSDqACCAiEEgEIgQxRCwBGmFDDLQCoFEgAgZ0SREBBggHgKEUSEEJYhQLFWBhjiiHBGAACFUYI4ACQzRimAlAYCCCi8MQgR4wlQxhAmLgLCQQ4VEgYRoQgAhiijhBFFCOAAMRwJBR0BAEFnkCQGCGBkFAIAQYDRgDABEDAAUScEEg9oAhgCDADlCGIUASsAYwQippQiAQAAlGJmCWQNIEQ4AQgw8FkHEQAAAEScQAqBbgQATgAAiMJWOUOAcEABACQw2CmRkMKICMkMEgARZhQxwwgCgFDMKKGAEAARIAAjxABDkXEEOGgAIBwUQaRRTBAlKFCUGbOAEUgRBYFByjlBgAGEOUMQEMgBQAw5QCoCjFACEAcaUIwQyyATQgBirCAUEUUEksI5BZAjwxDhECFMCiSYssAA4bRxgBGigFAQEsUUQcQYAgxQQCmFgAJCAGEEEAQJCwRRAChCHsRGMUGIRQYIYgBAxAggATEAAAodUIgQIAgwVCBFGUAAAMKcWAAxcwCABCEBMJAECACYcMpRJYSDUjjBBAMMIICVUgIx44AUCBHDEHFAEQSUU_ACgYADABijCAASMUGFcIQAgBWygAFBAHHAEeMJkZQIwohBBjBiHBAEGGQkgkwiJwU"); - fingerprint.Duration.Should().BeApproximately(85.11, 0.1); - } - - [TestCase("nin.mp3")] - [TestCase("nin.flac")] - public void should_lookup_file(string file) - { - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", file); - var localTrack = new LocalBook { Path = path }; - Subject.Lookup(new List { localTrack }, 0.5); - localTrack.AcoustIdResults.Should().NotBeNull(); - localTrack.AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - } - - [Test] - public void should_lookup_list() - { - var files = new[] - { - "nin.mp3", - "nin.flac" - }.Select(x => new LocalBook { Path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", x) }).ToList(); - Subject.Lookup(files, 0.5); - - files[0].AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - files[1].AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - } - - [Test] - public void should_lookup_list_when_fpcalc_fails_for_some_files() - { - var files = new[] - { - "nin.mp3", - "missing.mp3", - "nin.flac" - }.Select(x => new LocalBook { Path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", x) }).ToList(); - - var idpairs = files.Select(x => Tuple.Create(x, Subject.GetFingerprint(x.Path))).ToList(); - - Subject.Lookup(idpairs, 0.5); - - files[0].AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - files[1].AcoustIdResults.Should().BeNull(); - files[2].AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - } - - [Test] - public void should_lookup_list_when_fpcalc_fails_for_all_files() - { - var files = new[] - { - "missing1.mp3", - "missing2.mp3" - }.Select(x => new LocalBook { Path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", x) }).ToList(); - - var idpairs = files.Select(x => Tuple.Create(x, null)).ToList(); - - Subject.Lookup(idpairs, 0.5); - - files[0].AcoustIdResults.Should().BeNull(); - files[1].AcoustIdResults.Should().BeNull(); - } - - [Test] - public void should_not_fail_if_duration_reported_as_zero() - { - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "missing.mp3"); - var localTrack = new LocalBook { Path = path }; - var acoustId = new AcoustId - { - Duration = 0, - Fingerprint = "fingerprint" - }; - - Subject.Lookup(new List> { Tuple.Create(localTrack, acoustId) }, 0.5); - } - - [Test] - public void should_not_throw_if_fingerprint_invalid() - { - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "missing.mp3"); - var localTrack = new LocalBook { Path = path }; - var acoustId = new AcoustId - { - Duration = 1, - Fingerprint = "fingerprint" - }; - - var files = new List> { Tuple.Create(localTrack, acoustId) }; - Subject.Lookup(files, 0.5); - files[0].Item1.AcoustIdResults.Should().BeNull(); - } - - [Test] - public void should_not_fail_for_some_invalid_fingerprints() - { - var files = new[] - { - "nin.mp3", - "nin.flac" - }.Select(x => new LocalBook { Path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", x) }).ToList(); - - var idpairs = files.Select(x => Tuple.Create(x, Subject.GetFingerprint(x.Path))).ToList(); - - idpairs.Add(Tuple.Create(new LocalBook(), new AcoustId { Duration = 1, Fingerprint = "fingerprint" })); - - Subject.Lookup(idpairs, 0.5); - - idpairs[0].Item1.AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - idpairs[1].Item1.AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - idpairs[2].Item1.AcoustIdResults.Should().BeNull(); - } - - [Test] - public void should_not_throw_if_api_returns_html() - { - Mocker.GetMock().Setup(x => x.Post(It.IsAny())) - .Callback(req => throw new UnexpectedHtmlContentException(new HttpResponse(req, req.Headers, "html content", HttpStatusCode.Accepted))); - - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "nin.mp3"); - var localTrack = new LocalBook { Path = path }; - Subject.Lookup(new List { localTrack }, 0.5); - localTrack.AcoustIdResults.Should().BeNull(); - - ExceptionVerification.ExpectedWarns(4); - } - - [Test] - public void should_not_throw_if_api_times_out() - { - Mocker.GetMock().Setup(x => x.Post(It.IsAny())) - .Throws(new System.Net.WebException("The operation has timed out.")); - - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "nin.mp3"); - var localTrack = new LocalBook { Path = path }; - Subject.Lookup(new List { localTrack }, 0.5); - localTrack.AcoustIdResults.Should().BeNull(); - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_retry_if_too_many_requests() - { - var error = "{\"error\": {\"code\": 14, \"message\": \"rate limit (3 requests per second) exceeded, try again later\"}, \"status\": \"error\"}"; - var response = "{\"fingerprints\": [{\"index\": \"0\", \"results\": [{\"id\": \"a9b004fe-e161-417c-9f9e-443e4525334d\", \"recordings\": [{\"id\": \"209a4536-97ac-4e8a-aff1-1d39d029044b\"}, {\"id\": \"30f3f33e-8d0c-4e69-8539-cbd701d18f28\"}], \"score\": 0.940997}, {\"id\": \"fe0a9bec-2633-4c37-89be-b5d295b68a00\", \"score\": 0.763876}, {\"id\": \"18eab869-51dc-4948-83f7-4d8d441d5a1b\", \"score\": 0.490447}]}], \"status\": \"ok\"}"; - Mocker.GetMock() - .SetupSequence(o => o.Post(It.IsAny())) - .Returns(new HttpResponse(new HttpResponse(new HttpRequest("dummy"), new HttpHeader(), error, HttpStatusCode.ServiceUnavailable))) - .Returns(new HttpResponse(new HttpResponse(new HttpRequest("dummy"), new HttpHeader(), response, HttpStatusCode.OK))); - - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "nin.mp3"); - var localTrack = new LocalBook { Path = path }; - Subject.Lookup(new List { localTrack }, 0.5); - localTrack.AcoustIdResults.Should().NotBeNull(); - localTrack.AcoustIdResults.Should().Contain("30f3f33e-8d0c-4e69-8539-cbd701d18f28"); - - Mocker.GetMock() - .Verify(x => x.Post(It.IsAny()), Times.Exactly(2)); - } - - [Test] - public void should_not_retry_indefinitely_if_too_many_requests() - { - var error = "{\"error\": {\"code\": 14, \"message\": \"rate limit (3 requests per second) exceeded, try again later\"}, \"status\": \"error\"}"; - Mocker.GetMock() - .Setup(o => o.Post(It.IsAny())) - .Returns(new HttpResponse(new HttpResponse(new HttpRequest("dummy"), new HttpHeader(), error, HttpStatusCode.ServiceUnavailable))); - - var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "Media", "nin.mp3"); - var localTrack = new LocalBook { Path = path }; - - Subject.Lookup(new List { localTrack }, 0.5); - localTrack.AcoustIdResults.Should().BeNull(); - - Mocker.GetMock() - .Verify(x => x.Post(It.IsAny()), Times.Exactly(4)); - } - } -} diff --git a/src/NzbDrone.Core/HealthCheck/Checks/FpcalcCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/FpcalcCheck.cs deleted file mode 100644 index d4d4bdf71..000000000 --- a/src/NzbDrone.Core/HealthCheck/Checks/FpcalcCheck.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using NzbDrone.Core.Configuration; -using NzbDrone.Core.Configuration.Events; -using NzbDrone.Core.Localization; -using NzbDrone.Core.Parser; - -namespace NzbDrone.Core.HealthCheck.Checks -{ - [CheckOn(typeof(ConfigSavedEvent))] - public class FpcalcCheck : HealthCheckBase - { - private readonly IFingerprintingService _fingerprintingService; - private readonly IConfigService _configService; - - public FpcalcCheck(IFingerprintingService fingerprintingService, - IConfigService configService, - ILocalizationService localizationService) - : base(localizationService) - { - _fingerprintingService = fingerprintingService; - _configService = configService; - } - - public override HealthCheck Check() - { - // always pass if fingerprinting is disabled - if (_configService.AllowFingerprinting == AllowFingerprinting.Never) - { - return new HealthCheck(GetType()); - } - - if (!_fingerprintingService.IsSetup()) - { - return new HealthCheck(GetType(), HealthCheckResult.Warning, $"fpcalc could not be found. Audio fingerprinting disabled.", "#fpcalc-missing"); - } - - var fpcalcVersion = _fingerprintingService.FpcalcVersion(); - if (fpcalcVersion == null || fpcalcVersion < new Version("1.4.3")) - { - return new HealthCheck(GetType(), HealthCheckResult.Warning, $"You have an old version of fpcalc. Please upgrade to 1.4.3.", "#fpcalc-upgrade"); - } - - return new HealthCheck(GetType()); - } - } -} diff --git a/src/NzbDrone.Core/MediaFiles/BookImport/Identification/IdentificationTestCase.cs b/src/NzbDrone.Core/MediaFiles/BookImport/Identification/IdentificationTestCase.cs index 1ed184f02..9b9d7563c 100644 --- a/src/NzbDrone.Core/MediaFiles/BookImport/Identification/IdentificationTestCase.cs +++ b/src/NzbDrone.Core/MediaFiles/BookImport/Identification/IdentificationTestCase.cs @@ -16,12 +16,6 @@ namespace NzbDrone.Core.MediaFiles.BookImport.Identification public MetadataProfile MetadataProfile { get; set; } } - public class AcoustIdTestCase - { - public string Path { get; set; } - public List AcoustIdResults { get; set; } - } - public class IdTestCase { public List ExpectedMusicBrainzReleaseIds { get; set; } @@ -32,6 +26,5 @@ namespace NzbDrone.Core.MediaFiles.BookImport.Identification public bool NewDownload { get; set; } public bool SingleRelease { get; set; } public List Tracks { get; set; } - public List Fingerprints { get; set; } } } diff --git a/src/NzbDrone.Core/Parser/FingerprintingService.cs b/src/NzbDrone.Core/Parser/FingerprintingService.cs deleted file mode 100644 index c1ab00753..000000000 --- a/src/NzbDrone.Core/Parser/FingerprintingService.cs +++ /dev/null @@ -1,508 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using Newtonsoft.Json; -using NLog; -using NzbDrone.Common.Cache; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Common.Serializer; -using NzbDrone.Core.Parser.Model; - -namespace NzbDrone.Core.Parser -{ - public interface IFingerprintingService - { - bool IsSetup(); - Version FpcalcVersion(); - void Lookup(List tracks, double threshold); - } - - public class AcoustId - { - public double Duration { get; set; } - public string Fingerprint { get; set; } - } - - public class FingerprintingService : IFingerprintingService - { - private const string _acoustIdUrl = "https://api.acoustid.org/v2/lookup"; - private const string _acoustIdApiKey = "QANd68ji1L"; - private const int _fingerprintingTimeout = 10000; - - private readonly Logger _logger; - private readonly IHttpClient _httpClient; - private readonly IHttpRequestBuilderFactory _customerRequestBuilder; - private readonly ICached _cache; - - private readonly string _fpcalcPath; - private readonly Version _fpcalcVersion; - private readonly string _fpcalcArgs; - - public FingerprintingService(Logger logger, - IHttpClient httpClient, - ICacheManager cacheManager) - { - _logger = logger; - _httpClient = httpClient; - _cache = cacheManager.GetCache(GetType()); - - _customerRequestBuilder = new HttpRequestBuilder(_acoustIdUrl).CreateFactory(); - - // An exception here will cause Readarr to fail to start, so catch any errors - try - { - _fpcalcPath = GetFpcalcPath(); - - if (_fpcalcPath.IsNotNullOrWhiteSpace()) - { - _fpcalcVersion = GetFpcalcVersion(); - _fpcalcArgs = GetFpcalcArgs(); - } - } - catch (Exception ex) - { - _logger.Error(ex, "Somthing went wrong detecting fpcalc"); - } - } - - public bool IsSetup() => _fpcalcPath.IsNotNullOrWhiteSpace(); - public Version FpcalcVersion() => _fpcalcVersion; - - private string GetFpcalcPath() - { - string path = null; - - // Take the fpcalc from the install directory if it exists - path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fpcalc"); - if (OsInfo.IsWindows) - { - path += ".exe"; - } - - if (File.Exists(path)) - { - return path; - } - - // Otherwise search path for a candidate and check it works - if (OsInfo.IsLinux) - { - // must be on users path on Linux - path = "fpcalc"; - - // check that the command exists - Process p = new Process(); - p.StartInfo.FileName = path; - p.StartInfo.Arguments = "-version"; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - - try - { - p.Start(); - - // To avoid deadlocks, always read the output stream first and then wait. - string output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(1000); - } - catch - { - _logger.Debug("fpcalc not found"); - return null; - } - - return path; - } - else - { - // on OSX / Windows, we have put fpcalc in the application folder - _logger.Warn("fpcalc missing from application directory"); - return null; - } - } - - private Version GetFpcalcVersion() - { - if (_fpcalcPath == null) - { - return null; - } - - Process p = new Process(); - p.StartInfo.FileName = _fpcalcPath; - p.StartInfo.Arguments = $"-version"; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - - p.Start(); - - // To avoid deadlocks, always read the output stream first and then wait. - string output = p.StandardOutput.ReadToEnd(); - p.WaitForExit(1000); - - if (p.ExitCode != 0) - { - _logger.Warn("Could not get fpcalc version (may be known issue with fpcalc v1.4)"); - return null; - } - - var versionstring = Regex.Match(output, @"\d\.\d\.\d").Value; - if (versionstring.IsNullOrWhiteSpace()) - { - return null; - } - - var version = new Version(versionstring); - _logger.Debug($"fpcalc version: {version}"); - - return version; - } - - private string GetFpcalcArgs() - { - var args = ""; - - if (_fpcalcVersion == null) - { - return args; - } - - if (_fpcalcVersion >= new Version("1.4.0")) - { - args = "-json"; - } - - if (_fpcalcVersion >= new Version("1.4.3")) - { - args += " -ignore-errors"; - } - - return args; - } - - public AcoustId ParseFpcalcJsonOutput(string output) - { - return Json.Deserialize(output); - } - - public AcoustId ParseFpcalcTextOutput(string output) - { - var durationstring = Regex.Match(output, @"(?<=DURATION=)[\d\.]+(?=\s)").Value; - double duration; - if (durationstring.IsNullOrWhiteSpace() || !double.TryParse(durationstring, out duration)) - { - return null; - } - - var fingerprint = Regex.Match(output, @"(?<=FINGERPRINT=)[^\s]+").Value; - if (fingerprint.IsNullOrWhiteSpace()) - { - return null; - } - - return new AcoustId - { - Duration = duration, - Fingerprint = fingerprint - }; - } - - public AcoustId ParseFpcalcOutput(string output) - { - if (output.IsNullOrWhiteSpace()) - { - return null; - } - - if (_fpcalcArgs.Contains("-json")) - { - return ParseFpcalcJsonOutput(output); - } - else - { - return ParseFpcalcTextOutput(output); - } - } - - public AcoustId GetFingerprint(string file) - { - return _cache.Get(file, () => GetFingerprintUncached(file), TimeSpan.FromMinutes(30)); - } - - private AcoustId GetFingerprintUncached(string file) - { - if (IsSetup() && File.Exists(file)) - { - Process p = new Process(); - p.StartInfo.FileName = _fpcalcPath; - p.StartInfo.Arguments = $"{_fpcalcArgs} \"{file}\""; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.RedirectStandardError = true; - - _logger.Trace("Executing {0} {1}", p.StartInfo.FileName, p.StartInfo.Arguments); - - StringBuilder output = new StringBuilder(); - StringBuilder error = new StringBuilder(); - - // see https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why?lq=1 - // this is most likely overkill... - using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) - { - using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) - { - DataReceivedEventHandler outputHandler = (sender, e) => - { - if (e.Data == null) - { - outputWaitHandle.Set(); - } - else - { - output.AppendLine(e.Data); - } - }; - - DataReceivedEventHandler errorHandler = (sender, e) => - { - if (e.Data == null) - { - errorWaitHandle.Set(); - } - else - { - error.AppendLine(e.Data); - } - }; - - p.OutputDataReceived += outputHandler; - p.ErrorDataReceived += errorHandler; - - p.Start(); - - p.BeginOutputReadLine(); - p.BeginErrorReadLine(); - - if (p.WaitForExit(_fingerprintingTimeout) && - outputWaitHandle.WaitOne(_fingerprintingTimeout) && - errorWaitHandle.WaitOne(_fingerprintingTimeout)) - { - // Process completed. - if (p.ExitCode != 0) - { - _logger.Warn($"fpcalc error: {error}"); - return null; - } - else - { - return ParseFpcalcOutput(output.ToString()); - } - } - else - { - // Timed out. Remove handlers to avoid object disposed error - p.OutputDataReceived -= outputHandler; - p.ErrorDataReceived -= errorHandler; - - _logger.Warn($"fpcalc timed out. {error}"); - return null; - } - } - } - } - - return null; - } - - public void Lookup(List tracks, double threshold) - { - if (!IsSetup()) - { - return; - } - - Lookup(tracks.Select(x => Tuple.Create(x, GetFingerprint(x.Path))).ToList(), threshold); - } - - public void Lookup(List> files, double threshold) - { - var toLookup = files.Where(x => x.Item2 != null).ToList(); - if (!toLookup.Any()) - { - return; - } - - var request = GenerateRequest(toLookup); - var response = GetResponse(request); - ParseResponse(response, toLookup, threshold); - } - - public HttpRequest GenerateRequest(List> toLookup) - { - var httpRequest = _customerRequestBuilder.Create() - .WithRateLimit(0.334) - .Build(); - - var sb = new StringBuilder($"client={_acoustIdApiKey}&format=json&meta=recordingids&batch=1", 2000); - for (int i = 0; i < toLookup.Count; i++) - { - sb.Append($"&duration.{i}={toLookup[i].Item2.Duration:F0}&fingerprint.{i}={toLookup[i].Item2.Fingerprint}"); - } - - // they prefer a gzipped body - httpRequest.SetContent(Encoding.UTF8.GetBytes(sb.ToString()).Compress()); - httpRequest.Headers.Add("Content-Encoding", "gzip"); - httpRequest.Headers.ContentType = "application/x-www-form-urlencoded"; - httpRequest.SuppressHttpError = true; - httpRequest.RequestTimeout = TimeSpan.FromSeconds(5); - - return httpRequest; - } - - public LookupResponse GetResponse(HttpRequest request, int retry = 3) - { - HttpResponse httpResponse; - - try - { - httpResponse = _httpClient.Post(request); - } - catch (UnexpectedHtmlContentException e) - { - _logger.Warn(e, "AcoustId API gave invalid response"); - return retry > 0 ? GetResponse(request, retry - 1) : null; - } - catch (Exception e) - { - _logger.Warn(e, "AcoustId API lookup failed"); - return null; - } - - var response = httpResponse.Resource; - - if (httpResponse.HasHttpError || (response != null && response.Status != "ok")) - { - if (response?.Error != null) - { - if (response.Error.Code == AcoustIdErrorCode.TooManyRequests && retry > 0) - { - _logger.Trace($"Too many requests, retrying in 1s"); - Thread.Sleep(TimeSpan.FromSeconds(1)); - return GetResponse(request, retry - 1); - } - - _logger.Debug($"Webservice error {response.Error.Code}: {response.Error.Message}"); - } - else - { - _logger.Warn("HTTP Error - {0}", httpResponse); - } - - return null; - } - - return response; - } - - private void ParseResponse(LookupResponse response, List> toLookup, double threshold) - { - if (response == null) - { - return; - } - - // The API will give errors if fingerprint isn't found or is invalid. - // We don't want to stop the entire import because the fingerprinting failed - // so just log and return. - foreach (var fileResponse in response.Fingerprints) - { - if (fileResponse.Results.Count == 0) - { - _logger.Debug("No results for given fingerprint."); - continue; - } - - foreach (var result in fileResponse.Results.Where(x => x.Recordings != null)) - { - _logger.Trace("Found: {0}, {1}, {2}", result.Id, result.Score, string.Join(", ", result.Recordings.Select(x => x.Id))); - } - - var ids = fileResponse.Results.Where(x => x.Score > threshold && x.Recordings != null).SelectMany(y => y.Recordings.Select(z => z.Id)).Distinct().ToList(); - _logger.Trace("All recordings: {0}", string.Join("\n", ids)); - - toLookup[fileResponse.index].Item1.AcoustIdResults = ids; - } - - _logger.Debug("Fingerprinting complete."); - - var serializerSettings = Json.GetSerializerSettings(); - serializerSettings.Formatting = Formatting.None; - var output = new { Fingerprints = toLookup.Select(x => new { Path = x.Item1.Path, AcoustIdResults = x.Item1.AcoustIdResults }) }; - _logger.Debug($"*** FingerprintingService TestCaseGenerator ***\n{JsonConvert.SerializeObject(output, serializerSettings)}"); - } - - public class LookupResponse - { - public string Status { get; set; } - public LookupError Error { get; set; } - public List Fingerprints { get; set; } - } - - public enum AcoustIdErrorCode - { - // https://github.com/acoustid/acoustid-server/blob/f671339ad9ab049c4d4361d3eadb6660a8fe4dda/acoustid/api/errors.py#L10 - UnknownFormat = 1, - MissingParameter = 2, - InvalidFingerprint = 3, - InvalidApikey = 4, - Internal = 5, - InvalidUserApikey = 6, - InvalidUuid = 7, - InvalidDuration = 8, - InvalidBitrate = 9, - InvalidForeignid = 10, - InvalidMaxDurationDiff = 11, - NotAllowed = 12, - ServiceUnavailable = 13, - TooManyRequests = 14, - InvalidMusicbrainzAccessToken = 15, - InsecureRequest = 16, - UnknownApplication = 17, - FingerprintNotFound = 18 - } - - public class LookupError - { - public string Message { get; set; } - public AcoustIdErrorCode Code { get; set; } - } - - public class LookupResultListItem - { - public int index { get; set; } - public List Results { get; set; } - } - - public class LookupResult - { - public string Id { get; set; } - public double Score { get; set; } - public List Recordings { get; set; } - } - - public class RecordingResult - { - public string Id { get; set; } - } - } -} diff --git a/src/Runtimes/linux-arm/fpcalc b/src/Runtimes/linux-arm/fpcalc deleted file mode 100755 index 4ed72632f..000000000 Binary files a/src/Runtimes/linux-arm/fpcalc and /dev/null differ diff --git a/src/Runtimes/linux-arm64/fpcalc b/src/Runtimes/linux-arm64/fpcalc deleted file mode 100755 index 4ed72632f..000000000 Binary files a/src/Runtimes/linux-arm64/fpcalc and /dev/null differ diff --git a/src/Runtimes/linux-x64/fpcalc b/src/Runtimes/linux-x64/fpcalc deleted file mode 100755 index 201872c71..000000000 Binary files a/src/Runtimes/linux-x64/fpcalc and /dev/null differ diff --git a/src/Runtimes/osx-x64/fpcalc b/src/Runtimes/osx-x64/fpcalc deleted file mode 100755 index e8b3ae314..000000000 Binary files a/src/Runtimes/osx-x64/fpcalc and /dev/null differ diff --git a/src/Runtimes/win-x64/fpcalc.exe b/src/Runtimes/win-x64/fpcalc.exe deleted file mode 100755 index 94d7c81ec..000000000 Binary files a/src/Runtimes/win-x64/fpcalc.exe and /dev/null differ diff --git a/src/Runtimes/win-x86/fpcalc.exe b/src/Runtimes/win-x86/fpcalc.exe deleted file mode 100644 index 94d7c81ec..000000000 Binary files a/src/Runtimes/win-x86/fpcalc.exe and /dev/null differ diff --git a/src/SharedLiveTemplates.xml b/src/SharedLiveTemplates.xml deleted file mode 100644 index da03090c5..000000000 --- a/src/SharedLiveTemplates.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Targets/CopyRuntimes.targets b/src/Targets/CopyRuntimes.targets deleted file mode 100644 index 2479a6fbc..000000000 --- a/src/Targets/CopyRuntimes.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - -