Remove unused code

pull/1472/head
ta264 2 years ago
parent 6db135877a
commit 62a3355546

@ -1,5 +0,0 @@
{
"files.associations": {
"*.yaml": "home-assistant"
}
}

@ -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'))

5
debian/changelog vendored

@ -1,5 +0,0 @@
nzbdrone {version} {branch}; urgency=low
* Automatic Release.
-- NzbDrone <contact@nzbdrone.com> Mon, 26 Aug 2013 00:00:00 -0700

1
debian/compat vendored

@ -1 +0,0 @@
8

12
debian/control vendored

@ -1,12 +0,0 @@
Section: web
Priority: optional
Maintainer: Sonarr <contact@nzbdrone.com>
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

24
debian/copyright vendored

@ -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 <hello@readarr.com>
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 <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

1
debian/install vendored

@ -1 +0,0 @@
nzbdrone_bin/* opt/NzbDrone

13
debian/rules vendored

@ -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 $@

@ -1,4 +1,3 @@
<Project>
<Import Project="Targets/PublishAllRids.targets" />
<Import Project="Targets/CopyRuntimes.targets" />
</Project>

@ -1,30 +0,0 @@
using NzbDrone.Core.Blocklisting;
using NzbDrone.Core.Datastore;
using Sonarr.Http;
namespace NzbDrone.Api.Blocklist
{
public class BlocklistModule : SonarrRestModule<BlocklistResource>
{
private readonly BlocklistService _blocklistService;
public BlocklistModule(BlocklistService blocklistService)
{
_blocklistService = blocklistService;
GetResourcePaged = Blocklist;
DeleteResource = DeleteBlockList;
}
private PagingResource<BlocklistResource> Blocklist(PagingResource<BlocklistResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<BlocklistResource, Core.Blocklisting.Blocklist>("id", SortDirection.Ascending);
return ApplyToPage(_blocklistService.Paged, pagingSpec, BlocklistResourceMapper.MapToResource);
}
private void DeleteBlockList(int id)
{
_blocklistService.Delete(id);
}
}
}

@ -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<int> 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()
};
}
}
}

@ -125,19 +125,6 @@ namespace NzbDrone.Core.Test.MediaFiles.BookImport.Identification
return _authorService.FindById(foreignAuthorId);
}
private void GivenFingerprints(List<AcoustIdTestCase> fingerprints)
{
Mocker.GetMock<IConfigService>().Setup(x => x.AllowFingerprinting).Returns(AllowFingerprinting.AllFiles);
Mocker.GetMock<IFingerprintingService>().Setup(x => x.IsSetup()).Returns(true);
Mocker.GetMock<IFingerprintingService>()
.Setup(x => x.Lookup(It.IsAny<List<LocalBook>>(), It.IsAny<double>()))
.Callback((List<LocalBook> 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,

File diff suppressed because one or more lines are too long

@ -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());
}
}
}

@ -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<string> AcoustIdResults { get; set; }
}
public class IdTestCase
{
public List<string> 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<BasicLocalTrack> Tracks { get; set; }
public List<AcoustIdTestCase> Fingerprints { get; set; }
}
}

@ -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<LocalBook> 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<AcoustId> _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<AcoustId>(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<AcoustId>(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<LocalBook> tracks, double threshold)
{
if (!IsSetup())
{
return;
}
Lookup(tracks.Select(x => Tuple.Create(x, GetFingerprint(x.Path))).ToList(), threshold);
}
public void Lookup(List<Tuple<LocalBook, AcoustId>> 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<Tuple<LocalBook, AcoustId>> 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<LookupResponse> httpResponse;
try
{
httpResponse = _httpClient.Post<LookupResponse>(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<Tuple<LocalBook, AcoustId>> 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<LookupResultListItem> 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<LookupResult> Results { get; set; }
}
public class LookupResult
{
public string Id { get; set; }
public double Score { get; set; }
public List<RecordingResult> Recordings { get; set; }
}
public class RecordingResult
{
public string Id { get; set; }
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1 +0,0 @@
<TemplatesExport />

@ -1,11 +0,0 @@
<Project>
<ItemGroup>
<RuntimeFiles Include="..\Runtimes\$(RuntimeIdentifier)\*" />
</ItemGroup>
<Target Name="CopyRuntimeFilesOnBuild" AfterTargets="AfterBuild" Condition="!$(RuntimeIdentifier.StartsWith('linux')) or '$(TargetFramework)' == 'net6.0'">
<Copy SourceFiles="@(RuntimeFiles)" DestinationFolder="$(OutDir)" />
</Target>
<Target Name="CopyRuntimeFilesOnPublish" AfterTargets="Publish" Condition="!$(RuntimeIdentifier.StartsWith('linux')) or '$(TargetFramework)' == 'net6.0'">
<Copy SourceFiles="@(RuntimeFiles)" DestinationFolder="$(PublishDir)" />
</Target>
</Project>
Loading…
Cancel
Save