1
0
Fork 0

last clean code refactor

This commit is contained in:
Xavier Fontanet 2024-05-20 14:37:56 +02:00
parent 14c0573d1b
commit 395a5a8226
7 changed files with 90 additions and 98 deletions

View File

@ -42,7 +42,7 @@
<artifactId>resteasy-client</artifactId> <artifactId>resteasy-client</artifactId>
<version>3.5.0.Final</version> <version>3.5.0.Final</version>
</dependency> </dependency>
<!-- needed for java 17 compatibility -->
<dependency> <dependency>
<groupId>javax.xml</groupId> <groupId>javax.xml</groupId>
<artifactId>jaxb-api</artifactId> <artifactId>jaxb-api</artifactId>

View File

@ -18,7 +18,6 @@ public class ConfigFileLoader extends CommonConfigFileLoader<ConfigFileLoader.Pr
} }
public enum ProjectConfiguration { public enum ProjectConfiguration {
UPLOADS_PATHS
} }
@Override @Override

View File

@ -9,71 +9,75 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class FailedImportFixer { class FailedImportFixer {
public static final int MINIMUM_FILE_SIZE_TO_BE_CONSIDERED_A_VIDEO = 300000; static final int MINIMUM_FILE_SIZE_TO_BE_CONSIDERED_A_VIDEO = 300000;
private final Record queueRecord;
private final MissingFilesDetector missingFilesDetector = new MissingFilesDetector();
private final Path torrentPath;
private final Path seriePath;
private final FileCopier fileCopier; private final FileCopier fileCopier;
private Path seasonPath; private final MissingFilesDetector missingFilesDetector;
private final Path torrentPath;
private final String torrentTitle;
private final Path seasonPath;
static Factory factory() { static Factory factory() {
return new Factory(); return new Factory();
} }
public static class Factory { static class Factory {
FailedImportFixer newFixerFor(Record queueRecord, SonarrSerie serie){ FailedImportFixer newFixerFor(Record queueRecord, SonarrSerie serie){
return new FailedImportFixer(queueRecord, serie); return new FailedImportFixer(queueRecord, serie);
} }
} }
private FailedImportFixer(Record queueRecord, SonarrSerie serie) { private FailedImportFixer(Record queueRecord, SonarrSerie serie) {
this.queueRecord = queueRecord;
this.torrentPath = Path.of(queueRecord.getOutputPath());
this.seriePath = Path.of(serie.getPath());
fileCopier = new FileCopier(); fileCopier = new FileCopier();
missingFilesDetector = new MissingFilesDetector();
torrentPath = Path.of(queueRecord.getOutputPath());
torrentTitle = queueRecord.getTitle();
var seriePath = Path.of(serie.getPath());
seasonPath = seriePath.resolve(tryGettingSeasonFolder());
}
private String tryGettingSeasonFolder() {
try {
return StringCaptor.getSeasonFolderNameFromSeason(torrentTitle);
} catch (IncorrectWorkingReferencesException e) {
e.printStackTrace();
throw new SeasonFolderUnretrievable();
}
} }
void fix() throws IOException { void fix() throws IOException {
System.out.printf("%nfixing: %s%n" ,queueRecord.getTitle()); System.out.printf("%nfixing: %s%n" , torrentTitle);
List<Path> torrentFiles = resolveTorrentFiles(); List<Path> torrentFiles = getVideoFilesFrom(torrentPath);
List<Path> sonarFiles = resolveSonarrFiles(); List<Path> sonarFiles = getVideoFilesFrom(seasonPath);
List<Path> filesToCopy = missingFilesDetector.getMissingFilesAtDestination(torrentFiles, sonarFiles); List<Path> filesToCopy = missingFilesDetector.getMissingFilesAtDestination(torrentFiles, sonarFiles);
filesToCopy.forEach(this::copy); filesToCopy.forEach(this::copy);
} }
private List<Path> resolveTorrentFiles() throws IOException {
return getVideoFilesFrom(torrentPath);
}
private List<Path> resolveSonarrFiles() throws IOException {
seasonPath = seriePath.resolve(getSeasonFolder());
return getVideoFilesFrom(seasonPath);
}
private String getSeasonFolder() {
try {
return StringCaptor.getSeasonFolderNameFromSeason(torrentPath.getFileName().toString());
} catch (IncorrectWorkingReferencesException e) {
throw new RuntimeException(e);
}
}
private List<Path> getVideoFilesFrom(Path path) throws IOException { private List<Path> getVideoFilesFrom(Path path) throws IOException {
System.out.println("going to explore "+path); System.out.println("going to explore "+path);
try (var pathWalk = Files.walk(path, 3)) { try (var pathsWalk = Files.walk(path, 3)) {
return pathWalk return pathsWalk
.filter(p -> p.toFile().isFile()) .filter(this::isFile)
.filter(p -> p.toFile().length() > MINIMUM_FILE_SIZE_TO_BE_CONSIDERED_A_VIDEO) .filter(this::isAVideo)
.collect(Collectors.toList()); .toList();
} }
} }
private boolean isFile(Path path) {
return path.toFile().isFile();
}
private boolean isAVideo(Path path) {
return path.toFile().length() > MINIMUM_FILE_SIZE_TO_BE_CONSIDERED_A_VIDEO;
}
private void copy(Path fileToCopy) { private void copy(Path fileToCopy) {
Path target = seasonPath.resolve(fileToCopy.getFileName()); Path target = seasonPath.resolve(fileToCopy.getFileName());
System.out.println("** going to hardlink file to "+target); System.out.println("** going to hardlink file to "+target);
fileCopier.hardLink(fileToCopy, target); fileCopier.hardLink(fileToCopy, target);
} }
static class SeasonFolderUnretrievable extends RuntimeException {}
} }

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public class FileCopier { class FileCopier {
void hardLink(Path source, Path destination) { void hardLink(Path source, Path destination) {
try { try {
Files.createLink(destination, source); Files.createLink(destination, source);
@ -15,10 +15,3 @@ public class FileCopier {
} }
} }
} }
class ProjectPath {
static Path of(String path) {
String projectPath = System.getProperty("user.dir");
return Path.of(projectPath + path);
}
}

View File

@ -13,7 +13,7 @@ public class MainWorker {
worker.work(); worker.work();
} }
public MainWorker() throws IncorrectWorkingReferencesException { private MainWorker() throws IncorrectWorkingReferencesException {
var configLoader = ConfigFileLoader.getLoader(); var configLoader = ConfigFileLoader.getLoader();
Sonarr.initService(configLoader); Sonarr.initService(configLoader);
queueFixer = new QueueFixer(); queueFixer = new QueueFixer();

View File

@ -5,10 +5,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class MissingFilesDetector { class MissingFilesDetector {
private Map<Long, List<Path>> sonarrFilesByLength; private Map<Long, List<Path>> sonarrFilesByLength;
private Map<Long, List<Path>> torrentFileLengths; private Map<Long, List<Path>> torrentFilesByLength;
List<Path> getMissingFilesAtDestination(List<Path> torrentFiles, List<Path> sonarrFiles) { List<Path> getMissingFilesAtDestination(List<Path> torrentFiles, List<Path> sonarrFiles) {
System.out.printf("going to compare %d torrent files with %d sonar files%n", System.out.printf("going to compare %d torrent files with %d sonar files%n",
@ -19,8 +19,8 @@ public class MissingFilesDetector {
} }
private void digestTorrentFiles(List<Path> torrentFiles) { private void digestTorrentFiles(List<Path> torrentFiles) {
torrentFileLengths = getFileLengthsMapFrom(torrentFiles); torrentFilesByLength = getFileLengthsMapFrom(torrentFiles);
throwIfDuplicatedSizes(torrentFileLengths); throwIfDuplicatedSizes(torrentFilesByLength);
} }
private void digestSonarrFiles(List<Path> sonarrFiles) { private void digestSonarrFiles(List<Path> sonarrFiles) {
@ -28,35 +28,8 @@ public class MissingFilesDetector {
throwIfDuplicatedSizes(sonarrFilesByLength); throwIfDuplicatedSizes(sonarrFilesByLength);
} }
Map<Long, List<Path>> getFileLengthsMapFrom(List<Path> files) {
return files.stream()
.collect(Collectors.groupingBy(p -> p.toFile().length()));
}
private void throwIfDuplicatedSizes(Map<Long, List<Path>> torrentFileLengths) {
if (hasFilesWithSameSize(torrentFileLengths))
throw new InsecureScenario();
}
boolean hasFilesWithSameSize(Map<Long, List<Path>> torrentFileLengths) {
return torrentFileLengths
.values()
.stream()
.anyMatch(this::hasMultipleElements);
}
boolean hasMultipleElements(List<Path> paths) {
if (paths.size() > 1) {
var sampleFile = paths.get(0).toFile();
System.out.printf("!!! There is more than one file with the same size of %d. Name: %s %n",
sampleFile.length(), sampleFile.getName());
return true;
}
return false;
}
private List<Path> resolveMissingFiles() { private List<Path> resolveMissingFiles() {
return torrentFileLengths.entrySet() return torrentFilesByLength.entrySet()
.stream() .stream()
.filter(this::missingAtDestination) .filter(this::missingAtDestination)
.map(Map.Entry::getValue) .map(Map.Entry::getValue)
@ -64,6 +37,33 @@ public class MissingFilesDetector {
.toList(); .toList();
} }
Map<Long, List<Path>> getFileLengthsMapFrom(List<Path> files) {
return files.stream()
.collect(Collectors.groupingBy(p -> p.toFile().length()));
}
private void throwIfDuplicatedSizes(Map<Long, List<Path>> filesByLength) {
if (hasFilesWithSameSize(filesByLength))
throw new InsecureScenario();
}
boolean hasFilesWithSameSize(Map<Long, List<Path>> filesByLength) {
return filesByLength
.values()
.stream()
.anyMatch(this::hasMultipleElements);
}
boolean hasMultipleElements(List<Path> elements) {
if (elements.size() > 1) {
var sampleFile = elements.get(0).toFile();
System.out.printf("!!! There is more than one file with the same size of %d. Name: %s %n",
sampleFile.length(), sampleFile.getName());
return true;
}
return false;
}
private boolean missingAtDestination(Map.Entry<Long, List<Path>> torrentFileEntry) { private boolean missingAtDestination(Map.Entry<Long, List<Path>> torrentFileEntry) {
return !sonarrFilesByLength.containsKey(torrentFileEntry.getKey()); return !sonarrFilesByLength.containsKey(torrentFileEntry.getKey());
} }

View File

@ -9,22 +9,22 @@ import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class QueueFixer { public class QueueFixer {
final static String IMPORT_FAILURE_BECAUSE_MATCHED_BY_ID = "Found matching series via grab history, but release was matched to series by ID. Automatic import is not possible. See the FAQ for details."; final static String IMPORT_FAILURE_BECAUSE_MATCHED_BY_ID = "Found matching series via grab history, but release was matched to series by ID. Automatic import is not possible. See the FAQ for details.";
private final SonarrApiGateway sonarrApiGateway; private final SonarrApiGateway sonarrApiGateway;
private final FailedImportFixer.Factory failedImportFixerFactory; private final FailedImportFixer.Factory fixerFactory;
QueueFixer() { QueueFixer() {
sonarrApiGateway = Sonarr.api(); sonarrApiGateway = Sonarr.api();
failedImportFixerFactory = FailedImportFixer.factory(); fixerFactory = FailedImportFixer.factory();
} }
void fix() { void fix() {
List<Record> sonarQueue = retrieveQueueRecordsFromSonarr(); List<Record> sonarQueue = retrieveQueueRecordsFromSonarr();
Collection<Record> records = deduplicate(sonarQueue); var distinctRecords = deduplicate(sonarQueue);
List<Record> recordsToFix = filterFailedImportsOfIdProblem(records); var recordsToFix = filterFailedImportsOfIdProblem(distinctRecords);
recordsToFix.forEach(this::try2FixFailedImport); recordsToFix.forEach(this::try2FixFailedImport);
} }
@ -33,9 +33,9 @@ public class QueueFixer {
} }
private Collection<Record> deduplicate(List<Record> repetitiveRecords) { private Collection<Record> deduplicate(List<Record> repetitiveRecords) {
Map<String, Record> recordsByTitle = new HashMap<>(); var recordsByTitle = new HashMap<String, Record>();
repetitiveRecords.forEach(record -> for (var record : repetitiveRecords)
recordsByTitle.putIfAbsent(record.getTitle(), record)); recordsByTitle.putIfAbsent(record.getTitle(), record);
return recordsByTitle.values(); return recordsByTitle.values();
} }
@ -45,19 +45,13 @@ public class QueueFixer {
.toList(); .toList();
} }
private boolean recordsWithImportFailureBecauseIdMatching(Record record) {
return record.getStatusMessages().stream()
.flatMap(status -> status.getMessages().stream())
.anyMatch(IMPORT_FAILURE_BECAUSE_MATCHED_BY_ID::equals);
}
private void try2FixFailedImport(Record record) { private void try2FixFailedImport(Record record) {
try { try {
var seriesId = record.getSeriesId(); var seriesId = record.getSeriesId();
SonarrSerie serie = getSerieFromSonarr(seriesId); SonarrSerie serie = sonarrApiGateway.getSerieById(seriesId);
if (serie == null) return; if (serie == null) return;
failedImportFixerFactory fixerFactory
.newFixerFor(record, serie) .newFixerFor(record, serie)
.fix(); .fix();
} catch (IOException e) { } catch (IOException e) {
@ -66,8 +60,10 @@ public class QueueFixer {
} }
} }
private SonarrSerie getSerieFromSonarr(Integer seriesId) { private boolean recordsWithImportFailureBecauseIdMatching(Record record) {
return sonarrApiGateway.getSerieById(seriesId); return record.getStatusMessages().stream()
.flatMap(status -> status.getMessages().stream())
.anyMatch(IMPORT_FAILURE_BECAUSE_MATCHED_BY_ID::equals);
} }
} }