diff --git a/pom.xml b/pom.xml index 2212657f..ee23a17f 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ org.springframework.boot.loader.JarLauncher 17 19 + 3.1.14 src/main/java/drrename/PrimaryStageInitializer.java @@ -127,6 +128,11 @@ + + com.github.ulisesbocchio + jasypt-maven-plugin + 3.0.3 + @@ -189,6 +195,20 @@ jackson-dataformat-xml 2.13.4 + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-openfeign + 3.1.1 + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + 3.0.4 + diff --git a/src/main/java/drrename/DrRenameApplication.java b/src/main/java/drrename/DrRenameApplication.java index edbfa6ad..bd0e5b88 100644 --- a/src/main/java/drrename/DrRenameApplication.java +++ b/src/main/java/drrename/DrRenameApplication.java @@ -8,7 +8,6 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; -@Slf4j public class DrRenameApplication extends Application { private ConfigurableApplicationContext applicationContext; diff --git a/src/main/java/drrename/FileTypeByMimeProvider.java b/src/main/java/drrename/FileTypeByMimeProvider.java deleted file mode 100644 index 2638d530..00000000 --- a/src/main/java/drrename/FileTypeByMimeProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -package drrename; - -import lombok.extern.slf4j.Slf4j; -import org.apache.tika.Tika; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; - -@Slf4j -public class FileTypeByMimeProvider implements FileTypeProvider { - - public static String UNKNOWN = "n/a"; - - public static String DIRECTORY = "directory"; - - @Override - public String getFileType(Path path) { - final File file = path.toFile(); - if(Files.isDirectory(path)){ - return DIRECTORY; - } - try { - Tika tika = new Tika(); - @SuppressWarnings("") - var result = tika.detect(file); - return result; - } catch (Exception e) { - log.error(e.getLocalizedMessage(), e); - return UNKNOWN; - } - } -} diff --git a/src/main/java/drrename/GeneralExceptionHandler.java b/src/main/java/drrename/GeneralExceptionHandler.java index fb810fd7..85a38522 100644 --- a/src/main/java/drrename/GeneralExceptionHandler.java +++ b/src/main/java/drrename/GeneralExceptionHandler.java @@ -6,9 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.Arrays; import java.util.ResourceBundle; -import java.util.stream.Collectors; @Slf4j @Component @@ -22,21 +20,21 @@ private class Handler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { log.error("Uncaught exception on thread {}", t, e); + Platform.runLater(() -> showAlertDialog(e)); + } + + private void showAlertDialog(Throwable e) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle(String.format(resourceBundle.getString(ALERT_TITLE))); - alert.setHeaderText(e.toString()); - - TextArea area = new TextArea(Arrays.stream(e.getStackTrace()) - .map(StackTraceElement::toString) - .collect(Collectors.joining("\n"))); - + alert.setHeaderText(e.getLocalizedMessage()); + TextArea area = new TextArea(RenameUtil.stackTraceToString(e)); alert.getDialogPane().setContent(area); area.setWrapText(true); area.setEditable(false); alert.setResizable(true); - - - Platform.runLater(alert::showAndWait); + alert.getDialogPane().setPrefHeight(300); + alert.getDialogPane().setPrefWidth(400); + alert.showAndWait(); } } diff --git a/src/main/java/drrename/Launcher.java b/src/main/java/drrename/Launcher.java index d6fa6cbe..9cbe8bdb 100644 --- a/src/main/java/drrename/Launcher.java +++ b/src/main/java/drrename/Launcher.java @@ -1,5 +1,6 @@ package drrename; +import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties; import drrename.ui.ResourceBundleAwareLazyFxControllerAndViewResolver; import javafx.scene.Node; import lombok.extern.slf4j.Slf4j; @@ -9,6 +10,7 @@ import org.springframework.beans.factory.InjectionPoint; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; @@ -16,6 +18,8 @@ import java.util.ResourceBundle; @Slf4j +@EnableFeignClients +@EnableEncryptableProperties @SpringBootApplication public class Launcher { diff --git a/src/main/java/drrename/MovieDbChecker.java b/src/main/java/drrename/MovieDbChecker.java new file mode 100644 index 00000000..112d78eb --- /dev/null +++ b/src/main/java/drrename/MovieDbChecker.java @@ -0,0 +1,110 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename; + +import drrename.config.TheMovieDbConfig; +import drrename.kodi.nfo.MovieDbCheckType; +import drrename.model.themoviedb.SearchResultDto; +import drrename.model.themoviedb.TranslationDto; +import drrename.model.themoviedb.TranslationsDto; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Scope; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.io.IOError; +import java.io.IOException; +import java.time.LocalDate; +import java.util.*; + +@Getter +@Setter +@Slf4j +@Component +@Scope("prototype") +public class MovieDbChecker { + + private final MovieDbClient client; + + private final TheMovieDbConfig config; + + private final ResourceBundle resourceBundle; + + private Set onlineTitles; + + private String theMovieDbId; + + public MovieDbChecker(MovieDbClient client, TheMovieDbConfig config, ResourceBundle resourceBundle) { + this.client = client; + this.config = config; + this.resourceBundle = resourceBundle; + } + + protected void reset(){ + this.onlineTitles = new LinkedHashSet<>(); + this.theMovieDbId = null; + } + + public MovieDbCheckType check(String searchString, Integer year) throws IOException { + reset(); + var searchResult = client.searchMovie(config.getApiKey(), null, config.isIncludeAdult(), searchString, year); + ResponseEntity translatinos; + if(searchResult.getBody() != null && !searchResult.getBody().getResults().isEmpty()){ + SearchResultDto firstResult = searchResult.getBody().getResults().get(0); + getOnlineTitles().add(buildNameString(firstResult.getTitle(), firstResult.getReleaseDate())); + getOnlineTitles().add(buildNameString(firstResult.getOriginalTitle(), firstResult.getReleaseDate())); + if(searchString.equals(firstResult.getTitle())){ + theMovieDbId = firstResult.getPosterPath(); + return MovieDbCheckType.ORIGINAL_TITEL; + } + if(searchString.equals(firstResult.getOriginalTitle())){ + theMovieDbId = firstResult.getPosterPath(); + return MovieDbCheckType.ORIGINAL_TITEL; + } + translatinos = client.getTranslations(firstResult.getId(), config.getApiKey()); + if(translatinos.getBody() != null){ + for(TranslationDto translationDto : translatinos.getBody().getTranslations()){ + String iso1 = translationDto.getIso3166(); + String iso2 = translationDto.getIso639(); + String title = translationDto.getData().getTitle(); + if(resourceBundle.getLocale().getLanguage().equals(iso1) || resourceBundle.getLocale().getLanguage().equals(iso2)){ + getOnlineTitles().add(buildNameString(translationDto.getData().getTitle(), firstResult.getReleaseDate())); + } + if(searchString.equals(title)){ + theMovieDbId = firstResult.getPosterPath(); + return MovieDbCheckType.LOCALIZED_TITLE; + } + } + } else { + log.warn("Translations body is null"); + } + } + return MovieDbCheckType.NOT_FOUND; + } + + private String buildNameString(String title, LocalDate date) { + if(date == null){ + return title; + } + return title + " (" + date.getYear() + ")"; + } +} diff --git a/src/main/java/drrename/MovieDbClient.java b/src/main/java/drrename/MovieDbClient.java new file mode 100644 index 00000000..400cb39f --- /dev/null +++ b/src/main/java/drrename/MovieDbClient.java @@ -0,0 +1,39 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename; + +import drrename.model.themoviedb.SearchResultsDto; +import drrename.model.themoviedb.TranslationsDto; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(value = "moviedb", url = "${app.kodi.themoviedb.baseurl}", configuration = MovieDbClientConfig.class) +public interface MovieDbClient { + + @RequestMapping(method = RequestMethod.GET, value = "/search/movie", produces = "application/json") + ResponseEntity searchMovie(@RequestParam(name = "api_key") String apiKey, @RequestParam(name = "langauge", required = false) String language, @RequestParam(name = "include_adult", required = false) Boolean includeAdult, @RequestParam(name = "query") String query, @RequestParam(name = "year") Number year); + + @RequestMapping(method = RequestMethod.GET, value = "/movie/{id}/translations", produces = "application/json") + ResponseEntity getTranslations(@PathVariable(name = "id") Number id, @RequestParam(name = "api_key") String apiKey); +} diff --git a/src/main/java/drrename/MovieDbClientConfig.java b/src/main/java/drrename/MovieDbClientConfig.java new file mode 100644 index 00000000..34884de5 --- /dev/null +++ b/src/main/java/drrename/MovieDbClientConfig.java @@ -0,0 +1,34 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Bean; + +public class MovieDbClientConfig { + + @Bean + ObjectMapper objectMapper(){ + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper; + } +} diff --git a/src/main/java/drrename/MovieDbImagesClient.java b/src/main/java/drrename/MovieDbImagesClient.java new file mode 100644 index 00000000..ea4d4826 --- /dev/null +++ b/src/main/java/drrename/MovieDbImagesClient.java @@ -0,0 +1,36 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename; + +import drrename.model.themoviedb.SearchResultsDto; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(value = "moviedb-images", url = "${app.kodi.themoviedb.images.baseurl}", configuration = MovieDbClientConfig.class) +public interface MovieDbImagesClient { + + @RequestMapping(method = RequestMethod.GET, value = "/w500/{poster_path}", produces = MediaType.IMAGE_JPEG_VALUE) + ResponseEntity searchMovie(@RequestParam(name = "api_key") String apiKey, @RequestParam(name = "langauge", required = false) String language, @RequestParam(name = "include_adult", required = false) Boolean includeAdult, @PathVariable(name = "poster_path") String posterPath); +} diff --git a/src/main/java/drrename/RenameUtil.java b/src/main/java/drrename/RenameUtil.java index 2614e8c9..9c3ea4ae 100644 --- a/src/main/java/drrename/RenameUtil.java +++ b/src/main/java/drrename/RenameUtil.java @@ -1,27 +1,20 @@ package drrename; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import drrename.model.nfo.NfoFileXmlModel; -import lombok.extern.slf4j.Slf4j; - import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.stream.Collectors; -@Slf4j public class RenameUtil { - public static Path getImagePathFromNfo(Path nfoFile) throws IOException { - XmlMapper mapper = new XmlMapper(); - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - try { - NfoFileXmlModel xmlFileContent = mapper.readValue(nfoFile.toFile(), NfoFileXmlModel.class); - if(xmlFileContent.getArt() != null && xmlFileContent.getArt().getPoster() != null) - return nfoFile.getParent().resolve(xmlFileContent.getArt().getPoster()); - } catch (JsonParseException e) { - log.debug("Failed to deserialize image path from {})", nfoFile); - } - return null; + public static Path rename(final Path file, String newFileName) throws IOException { + return Files.move(file, file.resolveSibling(newFileName)); + } + + public static String stackTraceToString(Throwable e) { + return Arrays.stream(e.getStackTrace()) + .map(StackTraceElement::toString) + .collect(Collectors.joining("\n")); } } diff --git a/src/main/java/drrename/Strings.java b/src/main/java/drrename/Strings.java new file mode 100644 index 00000000..3017a87a --- /dev/null +++ b/src/main/java/drrename/Strings.java @@ -0,0 +1,51 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename; + +/** + * String helper functions. + * + * @author Gili Tzabari + */ +public final class Strings +{ + /** + * @param str a String + * @param prefix a prefix + * @return true if {@code start} starts with {@code prefix}, disregarding case sensitivity + */ + public static boolean startsWithIgnoreCase(String str, String prefix) + { + return str.regionMatches(true, 0, prefix, 0, prefix.length()); + } + + public static boolean endsWithIgnoreCase(String str, String suffix) + { + int suffixLength = suffix.length(); + return str.regionMatches(true, str.length() - suffixLength, suffix, 0, suffixLength); + } + + /** + * Prevent construction. + */ + private Strings() + { + } +} diff --git a/src/main/java/drrename/config/TheMovieDbConfig.java b/src/main/java/drrename/config/TheMovieDbConfig.java new file mode 100644 index 00000000..d550ded6 --- /dev/null +++ b/src/main/java/drrename/config/TheMovieDbConfig.java @@ -0,0 +1,37 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "app.kodi.themoviedb") +public class TheMovieDbConfig { + + String apiKey; + + String baseUrl; + + boolean includeAdult; + +} diff --git a/src/main/java/drrename/event/FilePreviewEvent.java b/src/main/java/drrename/event/FilePreviewEvent.java index e6e39d7c..b0e4eb8e 100644 --- a/src/main/java/drrename/event/FilePreviewEvent.java +++ b/src/main/java/drrename/event/FilePreviewEvent.java @@ -19,10 +19,8 @@ package drrename.event; -import drrename.model.RenamingEntry; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +import drrename.model.RenamingControl; -public record FilePreviewEvent(RenamingEntry renamingEntry) { +public record FilePreviewEvent(RenamingControl renamingControl) { } diff --git a/src/main/java/drrename/event/FileRenamedEvent.java b/src/main/java/drrename/event/FileRenamedEvent.java index 28b677ed..690d3d1e 100644 --- a/src/main/java/drrename/event/FileRenamedEvent.java +++ b/src/main/java/drrename/event/FileRenamedEvent.java @@ -19,7 +19,7 @@ package drrename.event; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -33,9 +33,9 @@ public class FileRenamedEvent { private final UUID uuid; - private final List renamedEntries; + private final List renamedEntries; - public FileRenamedEvent(UUID uuid, RenamingEntry renamedEntries) { + public FileRenamedEvent(UUID uuid, RenamingControl renamedEntries) { this(uuid, Collections.singletonList(renamedEntries)); } } diff --git a/src/main/java/drrename/event/NewRenamingEntryEvent.java b/src/main/java/drrename/event/NewRenamingEntryEvent.java index c1d5ca8a..5997bea9 100644 --- a/src/main/java/drrename/event/NewRenamingEntryEvent.java +++ b/src/main/java/drrename/event/NewRenamingEntryEvent.java @@ -19,7 +19,7 @@ package drrename.event; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import lombok.Data; import lombok.RequiredArgsConstructor; @@ -34,9 +34,9 @@ public class NewRenamingEntryEvent { private final UUID uuid; - private final List renamingEntries; + private final List renamingEntries; - public NewRenamingEntryEvent(UUID uuid, RenamingEntry renamingEntries) { + public NewRenamingEntryEvent(UUID uuid, RenamingControl renamingEntries) { this(uuid, Collections.singletonList(renamingEntries)); } } diff --git a/src/main/java/drrename/event/StageReadyEvent.java b/src/main/java/drrename/event/StageReadyEvent.java index 2cb49025..f4586736 100644 --- a/src/main/java/drrename/event/StageReadyEvent.java +++ b/src/main/java/drrename/event/StageReadyEvent.java @@ -20,8 +20,6 @@ package drrename.event; import javafx.stage.Stage; -import lombok.Data; -import lombok.RequiredArgsConstructor; public record StageReadyEvent(Stage stage) { diff --git a/src/main/java/drrename/event/StartingFileTypeEvent.java b/src/main/java/drrename/event/StartingFileTypeEvent.java index 334b79af..113cc9b1 100644 --- a/src/main/java/drrename/event/StartingFileTypeEvent.java +++ b/src/main/java/drrename/event/StartingFileTypeEvent.java @@ -1,6 +1,5 @@ package drrename.event; -import java.util.Objects; import java.util.UUID; public class StartingFileTypeEvent extends SynchronousUuidEvent { diff --git a/src/main/java/drrename/event/StartingListFilesEvent.java b/src/main/java/drrename/event/StartingListFilesEvent.java index bee4ea1a..8ddb4bd7 100644 --- a/src/main/java/drrename/event/StartingListFilesEvent.java +++ b/src/main/java/drrename/event/StartingListFilesEvent.java @@ -19,8 +19,6 @@ package drrename.event; -import lombok.Data; - import java.util.UUID; public class StartingListFilesEvent extends SynchronousUuidEvent { diff --git a/src/main/java/drrename/event/SynchronousUuidEvent.java b/src/main/java/drrename/event/SynchronousUuidEvent.java index d405c69e..cd00150f 100644 --- a/src/main/java/drrename/event/SynchronousUuidEvent.java +++ b/src/main/java/drrename/event/SynchronousUuidEvent.java @@ -22,7 +22,6 @@ import lombok.Data; import lombok.RequiredArgsConstructor; -import java.util.Objects; import java.util.UUID; @RequiredArgsConstructor diff --git a/src/main/java/drrename/filecreator/DummyFileCreatorController.java b/src/main/java/drrename/filecreator/DummyFileCreatorController.java index 3ce709af..517255b9 100644 --- a/src/main/java/drrename/filecreator/DummyFileCreatorController.java +++ b/src/main/java/drrename/filecreator/DummyFileCreatorController.java @@ -19,10 +19,10 @@ package drrename.filecreator; -import drrename.ui.mainview.GoCancelButtonsComponentController; -import drrename.ui.mainview.StartDirectoryComponentController; import drrename.event.DummyFileCreatorButtonCancelEvent; import drrename.event.DummyFileCreatorButtonGoEvent; +import drrename.ui.mainview.GoCancelButtonsComponentController; +import drrename.ui.mainview.StartDirectoryComponentController; import javafx.event.ActionEvent; import javafx.fxml.Initializable; import javafx.scene.Scene; @@ -36,13 +36,10 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.rgielen.fxweaver.core.FxmlView; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import java.net.URL; -import java.nio.file.Path; import java.util.ResourceBundle; @RequiredArgsConstructor diff --git a/src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResultTreeItemContent.java b/src/main/java/drrename/kodi/FixFailedException.java similarity index 59% rename from src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResultTreeItemContent.java rename to src/main/java/drrename/kodi/FixFailedException.java index 0c3c7699..b7ef0637 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResultTreeItemContent.java +++ b/src/main/java/drrename/kodi/FixFailedException.java @@ -17,21 +17,26 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi; -public class NfoCheckResultTreeItemContent extends CheckResultTreeItemContent { +public class FixFailedException extends Exception { - private boolean missingNfoIsAWarning; + public FixFailedException() { + } + + public FixFailedException(String message) { + super(message); + } - public NfoCheckResultTreeItemContent(T checkResult) { - super(checkResult); + public FixFailedException(String message, Throwable cause) { + super(message, cause); } - public boolean isMissingNfoIsAWarning() { - return missingNfoIsAWarning; + public FixFailedException(Throwable cause) { + super(cause); } - public void setMissingNfoIsAWarning(boolean missingNfoIsAWarning) { - this.missingNfoIsAWarning = missingNfoIsAWarning; + public FixFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); } } diff --git a/src/main/java/drrename/kodi/treeitem/KodiTreeRootItem.java b/src/main/java/drrename/kodi/KodiRootTreeItem.java similarity index 67% rename from src/main/java/drrename/kodi/treeitem/KodiTreeRootItem.java rename to src/main/java/drrename/kodi/KodiRootTreeItem.java index d05839ff..2b6e44be 100644 --- a/src/main/java/drrename/kodi/treeitem/KodiTreeRootItem.java +++ b/src/main/java/drrename/kodi/KodiRootTreeItem.java @@ -17,16 +17,20 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem; +package drrename.kodi; -import drrename.kodi.treeitem.content.KodiTreeItemContent; -import drrename.kodi.treeitem.content.KodiRootTreeItemContent; -import drrename.ui.FilterableTreeItem; +import javafx.scene.control.TreeView; -public class KodiTreeRootItem extends FilterableTreeItem { +import java.util.concurrent.Executor; - public KodiTreeRootItem() { - super(new KodiRootTreeItemContent()); - getValue().setTreeItem(this); +/** + * The root value of the Kodi {@link TreeView}. + * + * @see KodiRootTreeItemValue + */ +public class KodiRootTreeItem extends KodiTreeItem { + + public KodiRootTreeItem(Executor executor) { + super(new KodiRootTreeItemValue(executor)); } } diff --git a/src/main/java/drrename/kodi/treeitem/content/check/CheckResultTreeItemContent.java b/src/main/java/drrename/kodi/KodiRootTreeItemValue.java similarity index 54% rename from src/main/java/drrename/kodi/treeitem/content/check/CheckResultTreeItemContent.java rename to src/main/java/drrename/kodi/KodiRootTreeItemValue.java index 5cb70179..5707e3e4 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/CheckResultTreeItemContent.java +++ b/src/main/java/drrename/kodi/KodiRootTreeItemValue.java @@ -17,36 +17,40 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi; -import drrename.kodi.treeitem.content.KodiTreeItemContent; -import lombok.RequiredArgsConstructor; +import java.util.concurrent.Executor; -import java.util.Objects; - -@RequiredArgsConstructor -public class CheckResultTreeItemContent extends KodiTreeItemContent { +/** + * {@link KodiRootTreeItem}'s value. + * + * @see KodiRootTreeItem + */ +public class KodiRootTreeItemValue extends KodiTreeItemValue { - private final T checkResult; + public KodiRootTreeItemValue(Executor executor) { + super(null, false, executor); + setMessage("Analysis"); + setGraphic(null); + } - public T getCheckResult() { - return checkResult; + @Override + protected String updateMessage(Boolean newValue) { + return null; } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CheckResultTreeItemContent that)) return false; - return checkResult.equals(that.checkResult); + protected String updateIdentifier() { + return null; } @Override - public int hashCode() { - return Objects.hash(checkResult); + public void fix() throws FixFailedException { + throw new IllegalStateException("Cannot fix"); } @Override - public String toString() { - return checkResult.toString(); + protected void updateStatus() { + // nothing to update } } diff --git a/src/main/java/drrename/kodi/KodiToolsController.java b/src/main/java/drrename/kodi/KodiToolsController.java index 726bf714..723eac69 100644 --- a/src/main/java/drrename/kodi/KodiToolsController.java +++ b/src/main/java/drrename/kodi/KodiToolsController.java @@ -1,11 +1,7 @@ package drrename.kodi; -import drrename.RenameUtil; -import drrename.kodi.treeitem.content.check.NfoCheckResultTreeItemContent; -import drrename.kodi.treeitem.KodiTreeRootItem; -import drrename.kodi.treeitem.MovieTreeItemFactory; -import drrename.kodi.treeitem.content.KodiTreeItemContent; -import drrename.kodi.treeitem.content.MovieTreeItemContent; +import drrename.kodi.nfo.NfoFileTreeItemValue; +import drrename.model.RenamingPath; import drrename.ui.FXUtil; import drrename.ui.mainview.GoCancelButtonsComponentController; import drrename.ui.mainview.StartDirectoryComponentController; @@ -51,7 +47,7 @@ public class KodiToolsController implements Initializable { public ProgressBar progressBar; - public TreeView treeView; + public TreeView treeView; public Button buttonExpandAll; @@ -75,10 +71,12 @@ public class KodiToolsController implements Initializable { private final Executor executor; - private KodiTreeRootItem treeRoot; + private KodiRootTreeItem treeRoot; private final MovieTreeItemFactory movieTreeItemFactory; + private WarningsConfig warningsConfig; + @Override public void initialize(URL url, ResourceBundle resourceBundle) { mainStage = new Stage(); @@ -91,11 +89,11 @@ public void initialize(URL url, ResourceBundle resourceBundle) { goCancelButtonsComponentController.setButtonGoActionEventFactory(KodiToolsButtonGoEvent::new); progressBar.visibleProperty().bind(service.runningProperty()); - treeRoot = new KodiTreeRootItem(); + treeRoot = new KodiRootTreeItem(executor); treeView.setRoot(treeRoot); buttonExpandAll.setDisable(true); buttonCollapseAll.setDisable(true); - treeRoot.getChildren().addListener((ListChangeListener>) e -> { + treeRoot.getChildren().addListener((ListChangeListener>) e -> { buttonExpandAll.setDisable(e.getList().isEmpty()); buttonCollapseAll.setDisable(e.getList().isEmpty()); }); @@ -106,34 +104,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) { onButtonGoEvent(null); } }); - treeView.setCellFactory(tv -> new TreeCell<>() { - - @Override - protected void updateItem(KodiTreeItemContent item, boolean empty) { - super.updateItem(item, empty); - if (item == null) { - setText(null); - setStyle(null); - } else { - setText(item.toString()); - List styles = new ArrayList<>(); - if (item.hasWarning()) { - if (item instanceof MovieTreeItemContent) { - styles.add("-fx-font-size: 13;"); - } - styles.add("-fx-font-weight: bold;"); - styles.add("-fx-background-color: wheat;"); - var joinedStylesString = String.join(" ", styles); - setStyle(joinedStylesString); - } else { - if (item instanceof MovieTreeItemContent) { - styles.add("-fx-font-size: 14;"); - } else - setStyle(null); - } - } - } - }); + treeView.setCellFactory(this::treeViewCellFactoryCallback); treeView.getSelectionModel().getSelectedIndices().addListener((ListChangeListener) c -> { imageStage.close(); @@ -143,19 +114,26 @@ protected void updateItem(KodiTreeItemContent item, boolean empty) { } var hans = treeView.getTreeItem(c.getAddedSubList().get(0)).getValue(); log.debug("Selection changed: {} ({})", hans, hans.getClass()); - if (hans instanceof NfoCheckResultTreeItemContent peter) { + if (hans instanceof NfoFileTreeItemValue peter) { log.debug("Handling {}", peter); - Path nfoFile = peter.getCheckResult().getNfoFile(); - executor.execute(() -> showImage(nfoFile)); + Path nfoFile = peter.getNfoFile(); + executor.execute(() -> showImage(nfoFile)); } } }); + + warningsConfig = new WarningsConfig(); + warningsConfig.missingNfoFileIsWarningProperty().bind(checkBoxMissingNfoFileIsAWarning.selectedProperty()); + } + + private TreeCell treeViewCellFactoryCallback(TreeView kodiTreeItemContentTreeView) { + return new KodiTreeCell(treeView); } private void showImage(Path nfoFile) { if (nfoFile != null && Files.exists(nfoFile) && Files.isReadable(nfoFile)) { try { - Path imagePath = RenameUtil.getImagePathFromNfo(nfoFile); + Path imagePath = KodiUtil.getImagePathFromNfo(nfoFile); if (imagePath != null && Files.exists(imagePath) && Files.isReadable(imagePath)) { log.debug("Taking a look at {}", imagePath); Image image = new Image(imagePath.toFile().toURI().toString(), false); @@ -190,13 +168,13 @@ private void updateTreeRootPredicate() { Platform.runLater(() -> treeRoot.setPredicate(buildHideEmptyPredicate())); } - private Predicate buildHideEmptyPredicate() { + private Predicate buildHideEmptyPredicate() { return item -> { - if(item instanceof NfoCheckResultTreeItemContent anotherItem) - anotherItem.setMissingNfoIsAWarning(checkBoxMissingNfoFileIsAWarning.isSelected()); - if (checkBoxHideEmpty.isSelected()) - return item.hasWarning(); - return true; + var nfoFileIsWarning = checkBoxMissingNfoFileIsAWarning.isSelected(); + if(item instanceof NfoFileTreeItemValue item2){ + item2.setMissingNfoFileIsWarning(nfoFileIsWarning); + } + return item.isWarning() || !checkBoxHideEmpty.isSelected(); }; } @@ -239,11 +217,11 @@ private void handleResult(WorkerStateEvent workerStateEvent) { } } - private List> buildAndFillLevel1Items(List movieFolders) { - List> result = new ArrayList<>(); + private List> buildAndFillLevel1Items(List movieFolders) { + List> result = new ArrayList<>(); - for(Path moviePath : movieFolders){ - var item = movieTreeItemFactory.buildNew(moviePath); + for (Path moviePath : movieFolders) { + var item = movieTreeItemFactory.buildNew(new RenamingPath(moviePath), warningsConfig); result.add(item); } diff --git a/src/main/java/drrename/kodi/KodiTreeCell.java b/src/main/java/drrename/kodi/KodiTreeCell.java new file mode 100644 index 00000000..9672b257 --- /dev/null +++ b/src/main/java/drrename/kodi/KodiTreeCell.java @@ -0,0 +1,54 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import javafx.beans.binding.Bindings; +import javafx.scene.Node; +import javafx.scene.control.Control; +import javafx.scene.control.TreeCell; + +public class KodiTreeCell extends TreeCell { + + public KodiTreeCell(Control treeView) { + prefWidthProperty().bind(treeView.widthProperty().subtract(20.0)); + } + + @Override + protected void updateItem(KodiTreeItemValue item, boolean empty) { + + super.updateItem(item, empty); + if (item == null) { + textProperty().unbind(); + styleProperty().unbind(); + graphicProperty().unbind(); + setText(null); + setStyle(null); + setGraphic(null); + } else { + graphicProperty().bind(item.graphicProperty()); + textProperty().bind(Bindings.createStringBinding(() -> calculateMessageString(item), item.messageProperty())); + styleProperty().bind(item.styleProperty()); + } + } + + private String calculateMessageString(KodiTreeItemValue item) { + return (item.getIdentifer() != null ? item.getIdentifer() + ": " : "") + item.getMessage(); + } +} diff --git a/src/main/java/drrename/kodi/treeitem/KodiTreeItem.java b/src/main/java/drrename/kodi/KodiTreeItem.java similarity index 70% rename from src/main/java/drrename/kodi/treeitem/KodiTreeItem.java rename to src/main/java/drrename/kodi/KodiTreeItem.java index dfe0b415..f93434f3 100644 --- a/src/main/java/drrename/kodi/treeitem/KodiTreeItem.java +++ b/src/main/java/drrename/kodi/KodiTreeItem.java @@ -17,24 +17,27 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem; +package drrename.kodi; -import drrename.kodi.treeitem.content.KodiTreeItemContent; import drrename.ui.FilterableTreeItem; +import javafx.beans.Observable; import javafx.scene.control.TreeItem; +import lombok.extern.slf4j.Slf4j; -public class KodiTreeItem extends FilterableTreeItem { +@Slf4j +public class KodiTreeItem extends FilterableTreeItem { - public KodiTreeItem(KodiTreeItemContent value) { + public KodiTreeItem(KodiTreeItemValue value) { super(value); - getValue().setTreeItem(this); + value.setTreeItem(this); + graphicProperty().bind(value.graphicProperty()); } - public void add(KodiTreeItem childItem) { - getSourceChildren().add(childItem); + protected Observable[] getExtractorCallback(TreeItem item) { + return new Observable[]{item.getValue().getRenamingPath().movieNameProperty(), item.getValue().warningProperty()}; } - public boolean contains(KodiTreeItem childItem) { - return getSourceChildren().stream().map(TreeItem::getValue).anyMatch(v -> v.equals(childItem.getValue())); + public void add(KodiTreeItem childItem) { + getSourceChildren().add(childItem); } } diff --git a/src/main/java/drrename/kodi/KodiTreeItemValue.java b/src/main/java/drrename/kodi/KodiTreeItemValue.java new file mode 100644 index 00000000..5a040898 --- /dev/null +++ b/src/main/java/drrename/kodi/KodiTreeItemValue.java @@ -0,0 +1,289 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; +import javafx.application.Platform; +import javafx.beans.property.*; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.TreeItem; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.concurrent.Executor; + +/** + * Base class for all {@link KodiTreeItem} values. + * + * @see KodiTreeItem + */ +@Slf4j +public abstract class KodiTreeItemValue { + + private static final String warning_font = "-fx-font-weight: bold;"; + + private static final String warning_color = "-fx-background-color: wheat;"; + + private final ListProperty styles; + + private final StringProperty style; + + private final StringProperty buttonText; + + private final BooleanProperty canFix; + + private final ObjectProperty warning; + + private final StringProperty message; + + private final StringProperty identifer; + + private final ObjectProperty graphic; + + private final boolean fixable; + + private final WarningsConfig warningsConfig; + + private final RenamingPath renamingPath; + + private final ObjectProperty treeItem; + + private final Executor executor; + + public KodiTreeItemValue(RenamingPath moviePath, boolean fixable, Executor executor) { + this.renamingPath = moviePath; + this.fixable = fixable; + this.executor = executor; + this.buttonText = new SimpleStringProperty(); + this.canFix = new SimpleBooleanProperty(); + this.styles = new SimpleListProperty<>(FXCollections.observableArrayList()); + this.style = new SimpleStringProperty(); + this.warning = new SimpleObjectProperty<>(); + this.message = new SimpleStringProperty(); + this.graphic = new SimpleObjectProperty<>(); + this.treeItem = new SimpleObjectProperty<>(); + this.warningsConfig = new WarningsConfig(); + this.identifer = new SimpleStringProperty(); + init(); + } + + private void init() { + getStyles().addListener((ListChangeListener) c -> { + while (c.next()) { + setStyle(String.join(" ", c.getList())); + } + }); + canFixProperty().addListener((observable, oldValue, newValue) -> updateButtonText()); + warningProperty().addListener((observable, oldValue, newValue) -> { + updateStyles(newValue); + updateButtonText(); + setMessage(updateMessage(newValue)); + }); + setGraphic(buildGraphic()); + setIdentifer(updateIdentifier()); + } + + protected abstract String updateMessage(Boolean newValue); + + + public abstract void fix() throws FixFailedException; + + protected abstract String updateIdentifier(); + + protected void performFix() { + + executor.execute(() -> { + try { + fix(); + Platform.runLater(() -> updateStatus()); + } catch (FixFailedException e) { + throw new RuntimeException(e); + } + }); + } + + protected abstract void updateStatus(); + + protected void updateButtonText() { + updateButtonText(isCanFix(), isWarning()); + } + + protected void updateButtonText(boolean canFix, boolean isWarning) { + if (canFix) { + buttonText.set("Fix"); + } else if (isWarning) { + buttonText.set("Fix manually"); + } else { + buttonText.set("OK"); + } + } + + protected void updateStyles(Boolean warning) { + if (warning) { + styles.add(warning_font); + styles.add(warning_color); + } else { + styles.remove(warning_font); + styles.remove(warning_color); + } + } + + protected Node buildGraphic() { + Button button = new Button(); + button.textProperty().bind(buttonText); + button.disableProperty().bind(canFixProperty().not()); + button.setOnAction(actionEvent -> { + performFix(); + }); + return button; + } + + public boolean contains(KodiTreeItem childItem) { + return getTreeItem() != null && new ArrayList<>(getTreeItem().getSourceChildren()).stream().map(TreeItem::getValue).anyMatch(v -> v.equals(childItem.getValue())); + } + + // Getter / Setter // + + + public KodiTreeItem getTreeItem() { + return treeItem.get(); + } + + public ObjectProperty treeItemProperty() { + return treeItem; + } + + public void setTreeItem(KodiTreeItem treeItem) { + this.treeItem.set(treeItem); + } + + public String getMessage() { + return message.get(); + } + + public StringProperty messageProperty() { + return message; + } + + public void setMessage(String message) { + this.message.set(message); + } + + public boolean isWarning() { + return warning.get(); + } + + public ObjectProperty warningProperty() { + return warning; + } + + public void setWarning(boolean warning) { + this.warning.set(warning); + } + + public boolean isCanFix() { + return canFix.get(); + } + + public BooleanProperty canFixProperty() { + return canFix; + } + + public void setCanFix(boolean canFix) { + this.canFix.set(canFix); + } + + public boolean isFixable() { + return fixable; + } + + public String getStyle() { + return style.get(); + } + + public StringProperty styleProperty() { + return style; + } + + public void setStyle(String style) { + this.style.set(style); + } + + protected ObservableList getStyles() { + return styles.get(); + } + + protected ListProperty stylesProperty() { + return styles; + } + + protected void setStyles(ObservableList styles) { + this.styles.set(styles); + } + + public RenamingPath getRenamingPath() { + return renamingPath; + } + + + public String getButtonText() { + return buttonText.get(); + } + + public StringProperty buttonTextProperty() { + return buttonText; + } + + public void setButtonText(String buttonText) { + this.buttonText.set(buttonText); + } + + public Node getGraphic() { + return graphic.get(); + } + + public ObjectProperty graphicProperty() { + return graphic; + } + + public void setGraphic(Node graphic) { + this.graphic.set(graphic); + } + + public WarningsConfig getWarningsConfig() { + return warningsConfig; + } + + public String getIdentifer() { + return identifer.get(); + } + + public StringProperty identiferProperty() { + return identifer; + } + + public void setIdentifer(String identifer) { + this.identifer.set(identifer); + } +} diff --git a/src/main/java/drrename/kodi/KodiUtil.java b/src/main/java/drrename/kodi/KodiUtil.java new file mode 100644 index 00000000..6be4e8ca --- /dev/null +++ b/src/main/java/drrename/kodi/KodiUtil.java @@ -0,0 +1,62 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import drrename.model.nfo.NfoFileXmlModel; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Path; + +@Slf4j +public class KodiUtil { + + public static String getMovieNameFromDirectoryName(String directoryName){ + if(directoryName.contains("(")) { + return directoryName.substring(0, directoryName.indexOf("(")).trim(); + } + return directoryName; + } + + public static Integer getMovieYearFromDirectoryName(String directoryName) { + if(directoryName.contains("(")) { + return Integer.parseInt(directoryName.substring(directoryName.indexOf("(")+1, directoryName.indexOf(")")).trim()); + } + return null; + } + + public static Path getImagePathFromNfo(Path nfoFile) throws IOException { + XmlMapper mapper = new XmlMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + try { + NfoFileXmlModel xmlFileContent = mapper.readValue(nfoFile.toFile(), NfoFileXmlModel.class); + if(xmlFileContent.getArt() != null && xmlFileContent.getArt().getPoster() != null) + return nfoFile.getParent().resolve(xmlFileContent.getArt().getPoster()); + } catch (JsonParseException e) { + log.debug("Failed to deserialize image path from {})", nfoFile); + } + return null; + } + + +} diff --git a/src/main/java/drrename/kodi/MovieDbClientFactory.java b/src/main/java/drrename/kodi/MovieDbClientFactory.java new file mode 100644 index 00000000..33b7f7a3 --- /dev/null +++ b/src/main/java/drrename/kodi/MovieDbClientFactory.java @@ -0,0 +1,64 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.MovieDbChecker; +import drrename.MovieDbClient; +import drrename.MovieDbImagesClient; +import drrename.config.TheMovieDbConfig; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.ResourceBundle; + +@Component +public class MovieDbClientFactory { + + private final MovieDbClient client; + + private final MovieDbImagesClient imagesClient; + + private final TheMovieDbConfig config; + + private final ResourceBundle resourceBundle; + + public MovieDbClientFactory(MovieDbClient client, MovieDbImagesClient imagesClient, TheMovieDbConfig config, ResourceBundle resourceBundle) { + this.client = client; + this.imagesClient = imagesClient; + this.config = config; + this.resourceBundle = resourceBundle; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public MovieDbChecker getNewMovieDbChecker() { + return new MovieDbChecker(client, config, resourceBundle); + } + + public MovieDbImagesClient getImagesClient() { + return imagesClient; + } + + public TheMovieDbConfig getConfig() { + return config; + } +} diff --git a/src/main/java/drrename/kodi/MovieFileNameChecker.java b/src/main/java/drrename/kodi/MovieFileNameChecker.java new file mode 100644 index 00000000..7704993c --- /dev/null +++ b/src/main/java/drrename/kodi/MovieFileNameChecker.java @@ -0,0 +1,77 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.mime.FileTypeByMimeProvider; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Slf4j +public class MovieFileNameChecker { + + private List mediaFiles; + + public MovieFileNameType checkDir(Path directory) { + String movieName = directory.getFileName().toString(); + try { + setMediaFiles(findAllMediaFiles(directory)); + for(Path mediaFile : mediaFiles){ + String baseName = FilenameUtils.getBaseName(mediaFile.getFileName().toString()); + if(baseName.startsWith(movieName)){ + return MovieFileNameType.MATCHES_DIR_NAME; + } + } + if(!mediaFiles.isEmpty()){ + return MovieFileNameType.INVALID_MEDIA_FILE_NAME; + } + } catch (IOException e) { + log.error(e.getLocalizedMessage(), e); + return MovieFileNameType.EXCEPTION; + + } + return MovieFileNameType.NO_MEDIA_FILES_FOUND; + } + + private List findAllMediaFiles(Path directory) throws IOException { + List result = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(directory)) { + for (Path child : ds) { + if(Files.isRegularFile(child)){ + var mediaType = new FileTypeByMimeProvider().getFileType(child); + if(mediaType.startsWith("video")){ + result.add(child.getFileName()); + } + } + } + } + return result; + } +} diff --git a/src/main/java/drrename/kodi/MovieFileNameTreeItemValue.java b/src/main/java/drrename/kodi/MovieFileNameTreeItemValue.java new file mode 100644 index 00000000..d29c23b4 --- /dev/null +++ b/src/main/java/drrename/kodi/MovieFileNameTreeItemValue.java @@ -0,0 +1,90 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.concurrent.Executor; + +public class MovieFileNameTreeItemValue extends KodiTreeItemValue { + + private final ObjectProperty type; + + private final MovieFileNameChecker checker; + + public MovieFileNameTreeItemValue(RenamingPath path, Executor executor) { + super(path, true, executor); + this.type = new SimpleObjectProperty<>(); + checker = new MovieFileNameChecker(); + updateStatus(); + + } + + @Override + protected String updateMessage(Boolean newValue) { + if (getType() == null) { + return "unknown"; + } + if (newValue) { + return getType().toString() + (checker.getMediaFiles().isEmpty() ? "" : getWarningAdditionalInfo()); + } + return (getType().toString()); + } + + private String getWarningAdditionalInfo() { + return ": " + checker.getMediaFiles(); + } + + @Override + public void fix() throws FixFailedException { + throw new IllegalStateException("Cannot fix"); + } + + @Override + protected String updateIdentifier() { + return "Movie File Name"; + } + + @Override + protected void updateStatus() { + setType(checker.checkDir(getRenamingPath().getOldPath())); + setWarning(calculateWarning()); + } + + private boolean calculateWarning() { + return getType().isWarning(); + } + + // Getter / Setter // + + public MovieFileNameType getType() { + return type.get(); + } + + public ObjectProperty typeProperty() { + return type; + } + + public void setType(MovieFileNameType type) { + this.type.set(type); + } +} diff --git a/src/main/java/drrename/kodi/MovieFileNameType.java b/src/main/java/drrename/kodi/MovieFileNameType.java new file mode 100644 index 00000000..fd86300b --- /dev/null +++ b/src/main/java/drrename/kodi/MovieFileNameType.java @@ -0,0 +1,54 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +public enum MovieFileNameType { + MATCHES_DIR_NAME("Media file name matches directory name"), EXCEPTION("Failed to get media names"){ + @Override + boolean isWarning() { + return true; + } + }, NO_MEDIA_FILES_FOUND("No media files found"){ + @Override + boolean isWarning() { + return true; + } + }, INVALID_MEDIA_FILE_NAME("Invalid media file name"){ + @Override + boolean isWarning() { + return true; + } + }; + + private final String name; + + MovieFileNameType(String name){ + this.name = name; + } + + @Override + public String toString() { + return name; + } + + boolean isWarning(){ + return false; + } +} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResult.java b/src/main/java/drrename/kodi/MovieTreeItem.java similarity index 77% rename from src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResult.java rename to src/main/java/drrename/kodi/MovieTreeItem.java index e75b33cf..9856000f 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/NfoCheckResult.java +++ b/src/main/java/drrename/kodi/MovieTreeItem.java @@ -17,15 +17,13 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi; -import java.nio.file.Path; +public class MovieTreeItem extends KodiTreeItem { -public abstract class NfoCheckResult extends CheckResult { - - public NfoCheckResult(String result) { - super(result); + public MovieTreeItem(MovieTreeItemValue content) { + super(content); } - public abstract Path getNfoFile(); + } diff --git a/src/main/java/drrename/kodi/treeitem/MovieTreeItemFactory.java b/src/main/java/drrename/kodi/MovieTreeItemFactory.java similarity index 64% rename from src/main/java/drrename/kodi/treeitem/MovieTreeItemFactory.java rename to src/main/java/drrename/kodi/MovieTreeItemFactory.java index bfd08e93..9669824e 100644 --- a/src/main/java/drrename/kodi/treeitem/MovieTreeItemFactory.java +++ b/src/main/java/drrename/kodi/MovieTreeItemFactory.java @@ -17,14 +17,15 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem; +package drrename.kodi; -import drrename.kodi.treeitem.content.check.CheckServiceProvider; +import drrename.kodi.checkservice.CheckServiceProvider; +import drrename.model.RenamingPath; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.nio.file.Path; +import java.util.ArrayList; import java.util.concurrent.Executor; @Slf4j @@ -36,12 +37,13 @@ public class MovieTreeItemFactory { private final CheckServiceProvider checkServiceProvider; - public MovieTreeItem buildNew(Path moviePath){ - return triggerNfoFileNameCheck(new MovieTreeItem(moviePath)); + public MovieTreeItem buildNew(RenamingPath moviePath, WarningsConfig warningsConfig) { + return triggerChecks(new MovieTreeItem(new MovieTreeItemValue(moviePath, executor)), warningsConfig); } - private MovieTreeItem triggerNfoFileNameCheck(MovieTreeItem movieTreeItem) { - executor.execute(() -> checkServiceProvider.getCheckServices().forEach(e -> e.addChildItem(movieTreeItem))); + private MovieTreeItem triggerChecks(MovieTreeItem movieTreeItem, WarningsConfig warningsConfig) { + var listCopy = new ArrayList<>(checkServiceProvider.getCheckServices()); + executor.execute(() -> listCopy.forEach(e -> e.addChildItem(movieTreeItem, warningsConfig, executor))); return movieTreeItem; } } diff --git a/src/main/java/drrename/kodi/MovieTreeItemValue.java b/src/main/java/drrename/kodi/MovieTreeItemValue.java new file mode 100644 index 00000000..f2d2ca60 --- /dev/null +++ b/src/main/java/drrename/kodi/MovieTreeItemValue.java @@ -0,0 +1,73 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; +import javafx.beans.binding.Bindings; +import javafx.scene.control.TreeItem; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executor; + +@Slf4j +public class MovieTreeItemValue extends KodiTreeItemValue { + + public MovieTreeItemValue(RenamingPath moviePath, Executor executor) { + super(moviePath, false, executor); + moviePath.movieNameProperty().addListener((observableValue, s, t1) -> setMessage(t1)); + treeItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + initWarning(newValue); + } else { + warningProperty().unbind(); + } + }); + setMessage(moviePath.getMovieName()); + setGraphic(null); + } + + @Override + protected String updateIdentifier() { + return null; + } + + @Override + protected void updateStatus() { + // message is updated via binding to movie name property + } + + @Override + protected String updateMessage(Boolean newValue) { + return getRenamingPath().getMovieName(); + } + + @Override + public void fix() throws FixFailedException { + throw new IllegalStateException("Cannot fix"); + } + + protected void initWarning(KodiTreeItem treeItem) { + warningProperty().bind(Bindings.createBooleanBinding(() -> calculateWarning(treeItem), treeItem.getSourceChildren())); + } + + protected boolean calculateWarning(KodiTreeItem treeItem) { + return treeItem.getSourceChildren().stream().map(TreeItem::getValue).anyMatch(KodiTreeItemValue::isWarning); + } +} diff --git a/src/main/java/drrename/kodi/MultipleSpacesService.java b/src/main/java/drrename/kodi/MultipleSpacesService.java new file mode 100644 index 00000000..8a7a3edf --- /dev/null +++ b/src/main/java/drrename/kodi/MultipleSpacesService.java @@ -0,0 +1,33 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.kodi.checkservice.CheckService; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class MultipleSpacesService extends CheckService { + + @Override + public MultipleSpacesTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new MultipleSpacesTreeItemValue(path, executor); + } +} diff --git a/src/main/java/drrename/kodi/MultipleSpacesTreeItemValue.java b/src/main/java/drrename/kodi/MultipleSpacesTreeItemValue.java new file mode 100644 index 00000000..0d23a2ca --- /dev/null +++ b/src/main/java/drrename/kodi/MultipleSpacesTreeItemValue.java @@ -0,0 +1,68 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; +import drrename.strategy.RegexReplaceRenamingStrategy; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executor; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +public class MultipleSpacesTreeItemValue extends KodiTreeItemValue { + + public MultipleSpacesTreeItemValue(RenamingPath path, Executor executor) { + super(path, true, executor); + updateStatus(); + } + + @Override + protected String updateIdentifier() { + return "Movie Name Multiple Spaces"; + } + + @Override + protected String updateMessage(Boolean newValue) { + return isWarning() ? "Multiple spaces in path" : "No multiple spaces in path"; + } + + protected boolean calculateWarning() { + return test(getRenamingPath().getMovieName()); + } + + public boolean test(String fileName) { + Pattern p = Pattern.compile("\\s{2,}"); + Matcher m = p.matcher(fileName); + return m.find(); + } + + protected void updateStatus() { + setWarning(calculateWarning()); + setCanFix(isWarning()); + } + + public void fix() { + getRenamingPath().rename(new RegexReplaceRenamingStrategy(null).setReplacementStringFrom("\\s+").setReplacementStringTo(" ")); + } + + +} diff --git a/src/main/java/drrename/kodi/ProblematicMovieNameService.java b/src/main/java/drrename/kodi/ProblematicMovieNameService.java new file mode 100644 index 00000000..634e056b --- /dev/null +++ b/src/main/java/drrename/kodi/ProblematicMovieNameService.java @@ -0,0 +1,32 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.kodi.checkservice.CheckService; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class ProblematicMovieNameService extends CheckService { + @Override + public ProblematicMovieNameTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new ProblematicMovieNameTreeItemValue(path, executor); + } +} diff --git a/src/main/java/drrename/kodi/ProblematicMovieNameTreeItemValue.java b/src/main/java/drrename/kodi/ProblematicMovieNameTreeItemValue.java new file mode 100644 index 00000000..54fa8f62 --- /dev/null +++ b/src/main/java/drrename/kodi/ProblematicMovieNameTreeItemValue.java @@ -0,0 +1,57 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class ProblematicMovieNameTreeItemValue extends KodiTreeItemValue { + + public ProblematicMovieNameTreeItemValue(RenamingPath moviePath, Executor executor) { + super(moviePath, false, executor); + updateStatus(); + } + + @Override + protected String updateMessage(Boolean newValue) { + return isWarning() ? "Folder name problematic" : "Folder name unproblematic"; + } + + @Override + public void fix() throws FixFailedException { +throw new IllegalStateException("Cannot fix"); + } + + @Override + protected String updateIdentifier() { + return "Problematic Name"; + } + + @Override + protected void updateStatus() { + setWarning(calculateWarning()); + setCanFix(isWarning()); + } + + private boolean calculateWarning() { + return getRenamingPath().getMovieName().startsWith("."); + } +} diff --git a/src/main/java/drrename/kodi/SubdirsTreeItemValue.java b/src/main/java/drrename/kodi/SubdirsTreeItemValue.java new file mode 100644 index 00000000..79341410 --- /dev/null +++ b/src/main/java/drrename/kodi/SubdirsTreeItemValue.java @@ -0,0 +1,145 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import drrename.model.RenamingPath; +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.Executor; + +@Slf4j +public class SubdirsTreeItemValue extends KodiTreeItemValue { + + private final ListProperty subdirs; + + public SubdirsTreeItemValue(RenamingPath moviePath, Executor executor) { + super(moviePath, false, executor); + subdirs = new SimpleListProperty<>(); + init(); + updateStatus(); + } + + private void init(){ + subdirs.addListener((ListChangeListener) c -> { + while(c.next()){ + setWarning(calculateWarning(c.getList())); + setCanFix(isWarning()); + } + }); + } + + @Override + protected String updateIdentifier() { + return "Subdirs"; + } + + @Override + protected void updateStatus() { + try { + setSubdirs(FXCollections.observableArrayList(getSubdirs(getRenamingPath().getOldPath()))); + } catch (IOException e) { + log.error(e.getLocalizedMessage(), e); + } + } + + protected List getSubdirs(Path path) throws IOException { + List subdirs = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(path)) { + for (Path child : ds) { + if (Files.isDirectory(child)) { + subdirs.add(child); + } + } + } + return subdirs; + } + + protected List getChildFilesAndFolders(Path path) throws IOException { + List subdirs = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(path)) { + for (Path child : ds) { + subdirs.add(child); + } + } + return subdirs; + } + + protected String countChildFilesAndFolders(Path path) { + try { + return Integer.toString(getChildFilesAndFolders(path).size()); + } catch (IOException e) { + return e.getLocalizedMessage(); + } + } + + private boolean calculateWarning(Collection subdirs){ + return !subdirs.isEmpty(); + } + + @Override + protected String updateMessage(Boolean newValue) { + return newValue ? "Has subdirs: " + getSubdirs().stream().map(p -> p.getFileName() + "[" + countChildFilesAndFolders(p) + "]").toList() : "No subdirs"; + } + + @Override + public void fix() throws FixFailedException { + for(Path p : getSubdirs()){ + try (var dirStream = Files.walk(p)) { + dirStream + .map(Path::toFile) + .sorted(Comparator.reverseOrder()) + .forEach(File::delete); + } catch (IOException e) { + throw new FixFailedException(e); + } + } + } + + + + // Getter / Setter // + + + public ObservableList getSubdirs() { + return subdirs.get(); + } + + public ListProperty subdirsProperty() { + return subdirs; + } + + public void setSubdirs(ObservableList subdirs) { + this.subdirs.set(subdirs); + } +} diff --git a/src/main/java/drrename/kodi/treeitem/content/KodiTreeItemContent.java b/src/main/java/drrename/kodi/WarningsConfig.java similarity index 56% rename from src/main/java/drrename/kodi/treeitem/content/KodiTreeItemContent.java rename to src/main/java/drrename/kodi/WarningsConfig.java index 54725a8c..f56dc6cd 100644 --- a/src/main/java/drrename/kodi/treeitem/content/KodiTreeItemContent.java +++ b/src/main/java/drrename/kodi/WarningsConfig.java @@ -17,28 +17,30 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content; +package drrename.kodi; -import javafx.scene.control.TreeItem; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +public class WarningsConfig { -public abstract class KodiTreeItemContent { + private final BooleanProperty missingNfoFileIsWarning; - private TreeItem treeItem; - - public boolean hasWarning() { - return treeItem != null && treeItem.getChildren().stream().map(TreeItem::getValue).anyMatch(KodiTreeItemContent::hasWarning); + public WarningsConfig(){ + this.missingNfoFileIsWarning = new SimpleBooleanProperty(); } // Getter / Setter // - @SuppressWarnings("unused") - public TreeItem getTreeItem() { - return treeItem; + public boolean isMissingNfoFileIsWarning() { + return missingNfoFileIsWarning.get(); + } + + public BooleanProperty missingNfoFileIsWarningProperty() { + return missingNfoFileIsWarning; } - public KodiTreeItemContent setTreeItem(TreeItem treeItem) { - this.treeItem = treeItem; - return this; + public void setMissingNfoFileIsWarning(boolean missingNfoFileIsWarning) { + this.missingNfoFileIsWarning.set(missingNfoFileIsWarning); } } diff --git a/src/main/java/drrename/kodi/checkservice/CheckService.java b/src/main/java/drrename/kodi/checkservice/CheckService.java new file mode 100644 index 00000000..1a998647 --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/CheckService.java @@ -0,0 +1,48 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.KodiTreeItem; +import drrename.kodi.KodiTreeItemValue; +import drrename.kodi.MovieTreeItem; +import drrename.kodi.WarningsConfig; +import drrename.model.RenamingPath; +import javafx.application.Platform; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.Executor; + +@Slf4j +public abstract class CheckService { + + public void addChildItem(MovieTreeItem treeItem, WarningsConfig warningsConfig, Executor executor) { + + R checkResult = checkPath(treeItem.getValue().getRenamingPath(), warningsConfig, executor); + var childItem = buildChildItem(checkResult); + Platform.runLater(() -> treeItem.add(childItem)); + + } + + public abstract R checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor); + + public KodiTreeItem buildChildItem(R checkResult) { + return new KodiTreeItem(checkResult); + } +} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/CheckServiceProvider.java b/src/main/java/drrename/kodi/checkservice/CheckServiceProvider.java similarity index 63% rename from src/main/java/drrename/kodi/treeitem/content/check/CheckServiceProvider.java rename to src/main/java/drrename/kodi/checkservice/CheckServiceProvider.java index bd9d3383..3f7135d4 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/CheckServiceProvider.java +++ b/src/main/java/drrename/kodi/checkservice/CheckServiceProvider.java @@ -17,25 +17,35 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi.checkservice; -import drrename.kodi.treeitem.content.NfoFileContentCheckService; +import drrename.kodi.MultipleSpacesService; +import drrename.kodi.ProblematicMovieNameService; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; - +/** + * Holds all {@link CheckService} instances that should run. + */ @Service public class CheckServiceProvider { private final List> checkServices; - public CheckServiceProvider(){ + public CheckServiceProvider(NfoFileContentUrlCheckService nfoFileContentUrlCheckService){ + this.checkServices = Arrays.asList( + nfoFileContentUrlCheckService, + new MovieFileNameCheckService(), new NfoFileNameCheckService(), - new NfoFileContentCheckService(), - new SubdirsCheckService() + new NfoFileContentYearCheckService(), + new NfoFileContentTitleCheckService(), + new NfoFileContentCoverCheckService(), + new SubdirsCheckService(), + new MultipleSpacesService(), + new ProblematicMovieNameService() ); } diff --git a/src/main/java/drrename/kodi/checkservice/MovieFileNameCheckService.java b/src/main/java/drrename/kodi/checkservice/MovieFileNameCheckService.java new file mode 100644 index 00000000..df6bd274 --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/MovieFileNameCheckService.java @@ -0,0 +1,34 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.MovieFileNameTreeItemValue; +import drrename.kodi.WarningsConfig; +import drrename.kodi.checkservice.CheckService; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class MovieFileNameCheckService extends CheckService { + @Override + public MovieFileNameTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new MovieFileNameTreeItemValue(path, executor); + } +} diff --git a/src/main/java/drrename/kodi/checkservice/NfoFileContentCoverCheckService.java b/src/main/java/drrename/kodi/checkservice/NfoFileContentCoverCheckService.java new file mode 100644 index 00000000..7f5de49b --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/NfoFileContentCoverCheckService.java @@ -0,0 +1,36 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.WarningsConfig; +import drrename.kodi.nfo.NfoFileContentCoverTreeItemValue; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class NfoFileContentCoverCheckService extends CheckService { + + public NfoFileContentCoverTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new NfoFileContentCoverTreeItemValue(path, executor); + + } + + +} diff --git a/src/main/java/drrename/kodi/checkservice/NfoFileContentTitleCheckService.java b/src/main/java/drrename/kodi/checkservice/NfoFileContentTitleCheckService.java new file mode 100644 index 00000000..8b96ab61 --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/NfoFileContentTitleCheckService.java @@ -0,0 +1,36 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.WarningsConfig; +import drrename.kodi.nfo.NfoFileContentTitleTreeItemValue; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class NfoFileContentTitleCheckService extends CheckService { + + public NfoFileContentTitleTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new NfoFileContentTitleTreeItemValue(path, executor); + + } + + +} diff --git a/src/main/java/drrename/kodi/checkservice/NfoFileContentUrlCheckService.java b/src/main/java/drrename/kodi/checkservice/NfoFileContentUrlCheckService.java new file mode 100644 index 00000000..5700de9a --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/NfoFileContentUrlCheckService.java @@ -0,0 +1,44 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.MovieDbClientFactory; +import drrename.kodi.WarningsConfig; +import drrename.kodi.nfo.NfoFileContentUrlTreeItemValue; +import drrename.model.RenamingPath; +import org.springframework.stereotype.Component; + +import java.util.concurrent.Executor; + +@Component +public class NfoFileContentUrlCheckService extends CheckService { + + private final MovieDbClientFactory factory; + + public NfoFileContentUrlCheckService(MovieDbClientFactory factory) { + + this.factory = factory; + } + + @Override + public NfoFileContentUrlTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new NfoFileContentUrlTreeItemValue(path, executor, factory); + } +} diff --git a/src/main/java/drrename/kodi/checkservice/NfoFileContentYearCheckService.java b/src/main/java/drrename/kodi/checkservice/NfoFileContentYearCheckService.java new file mode 100644 index 00000000..ebee2628 --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/NfoFileContentYearCheckService.java @@ -0,0 +1,36 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.WarningsConfig; +import drrename.kodi.nfo.NfoFileContentYearTreeItemValue; +import drrename.model.RenamingPath; + +import java.util.concurrent.Executor; + +public class NfoFileContentYearCheckService extends CheckService { + + public NfoFileContentYearTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new NfoFileContentYearTreeItemValue(path, executor); + + } + + +} diff --git a/src/main/java/drrename/kodi/checkservice/NfoFileNameCheckService.java b/src/main/java/drrename/kodi/checkservice/NfoFileNameCheckService.java new file mode 100644 index 00000000..41d7fdf8 --- /dev/null +++ b/src/main/java/drrename/kodi/checkservice/NfoFileNameCheckService.java @@ -0,0 +1,38 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.checkservice; + +import drrename.kodi.WarningsConfig; +import drrename.kodi.nfo.NfoFileNameTreeItemValue; +import drrename.model.RenamingPath; + +import java.nio.file.Files; +import java.util.concurrent.Executor; + +public class NfoFileNameCheckService extends CheckService { + + @Override + public NfoFileNameTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + if (!Files.isDirectory(path.getOldPath())) { + throw new IllegalArgumentException(path.getMovieName() + " is not a directory"); + } + return new NfoFileNameTreeItemValue(path, warningsConfig, executor); + } +} diff --git a/src/main/java/drrename/kodi/treeitem/content/NfoFileContentTreeItemContent.java b/src/main/java/drrename/kodi/checkservice/SubdirsCheckService.java similarity index 62% rename from src/main/java/drrename/kodi/treeitem/content/NfoFileContentTreeItemContent.java rename to src/main/java/drrename/kodi/checkservice/SubdirsCheckService.java index 9e9f0dda..6694eedb 100644 --- a/src/main/java/drrename/kodi/treeitem/content/NfoFileContentTreeItemContent.java +++ b/src/main/java/drrename/kodi/checkservice/SubdirsCheckService.java @@ -17,19 +17,19 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content; +package drrename.kodi.checkservice; -import drrename.kodi.treeitem.content.check.NfoFileContentCheckResult; -import drrename.kodi.treeitem.content.check.NfoCheckResultTreeItemContent; +import drrename.kodi.SubdirsTreeItemValue; +import drrename.kodi.WarningsConfig; +import drrename.kodi.checkservice.CheckService; +import drrename.model.RenamingPath; -public class NfoFileContentTreeItemContent extends NfoCheckResultTreeItemContent { +import java.util.concurrent.Executor; - public NfoFileContentTreeItemContent(NfoFileContentCheckResult value) { - super(value); - } +public class SubdirsCheckService extends CheckService { @Override - public boolean hasWarning() { - return getCheckResult().isWarning(); + public SubdirsTreeItemValue checkPath(RenamingPath path, WarningsConfig warningsConfig, Executor executor) { + return new SubdirsTreeItemValue(path, executor); } } diff --git a/src/main/java/drrename/kodi/treeitem/content/MovieTreeItemContent.java b/src/main/java/drrename/kodi/nfo/MovieDbCheckType.java similarity index 67% rename from src/main/java/drrename/kodi/treeitem/content/MovieTreeItemContent.java rename to src/main/java/drrename/kodi/nfo/MovieDbCheckType.java index 6e979f56..81047c1a 100644 --- a/src/main/java/drrename/kodi/treeitem/content/MovieTreeItemContent.java +++ b/src/main/java/drrename/kodi/nfo/MovieDbCheckType.java @@ -17,24 +17,30 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content; +package drrename.kodi.nfo; -import java.nio.file.Path; +public enum MovieDbCheckType { -public class MovieTreeItemContent extends KodiTreeItemContent { + NOT_FOUND("Not found"){ + @Override + public boolean isWarning() { + return true; + } + }, + ORIGINAL_TITEL("Original title"), LOCALIZED_TITLE("Localized title"); - private final Path moviePath; + private final String name; - public MovieTreeItemContent(Path moviePath) { - this.moviePath = moviePath; + MovieDbCheckType(String name){ + this.name = name; } @Override public String toString() { - return moviePath.getFileName().toString(); + return name; } - public Path getMoviePath() { - return moviePath; + public boolean isWarning() { + return false; } } diff --git a/src/main/java/drrename/kodi/treeitem/content/KodiRootTreeItemContent.java b/src/main/java/drrename/kodi/nfo/NfoChecker.java similarity index 72% rename from src/main/java/drrename/kodi/treeitem/content/KodiRootTreeItemContent.java rename to src/main/java/drrename/kodi/nfo/NfoChecker.java index 26908073..760a2f70 100644 --- a/src/main/java/drrename/kodi/treeitem/content/KodiRootTreeItemContent.java +++ b/src/main/java/drrename/kodi/nfo/NfoChecker.java @@ -17,21 +17,22 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content; +package drrename.kodi.nfo; -public class KodiRootTreeItemContent extends KodiTreeItemContent { +import lombok.Getter; +import lombok.Setter; - public KodiRootTreeItemContent() { +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; - } +@Getter +@Setter +public class NfoChecker { - @Override - public boolean hasWarning() { - return false; - } + private List nfoFiles; - @Override - public String toString() { - return "Analysis Result"; + public NfoChecker(){ + nfoFiles = new ArrayList<>(); } } diff --git a/src/main/java/drrename/kodi/nfo/NfoContentChecker.java b/src/main/java/drrename/kodi/nfo/NfoContentChecker.java new file mode 100644 index 00000000..24396fb3 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoContentChecker.java @@ -0,0 +1,58 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.model.nfo.NfoRoot; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +@Slf4j +public abstract class NfoContentChecker extends NfoChecker { + + public NfoFileContentType checkNfoFile(Path nfoFile){ + if(Files.notExists(nfoFile)){ + return NfoFileContentType.NO_FILE; + } + if(!Files.isReadable(nfoFile)){ + return NfoFileContentType.EXCEPTION; + } + if(!Files.isRegularFile(nfoFile)){ + return NfoFileContentType.NOT_A_FILE; + } + try { + NfoRoot xmlModel = new NfoFileParser().parse(nfoFile); + if(xmlModel == null || (xmlModel.getMovie() == null && xmlModel.getUrl() == null)){ + return NfoFileContentType.INVALID_FILE; + } + if(xmlModel.getMovie() == null && xmlModel.getUrl() != null){ + return NfoFileContentType.URL_ONLY_FILE; + } + return doCheckNfoFile(nfoFile.getParent(), xmlModel); + } catch (IOException e) { + log.debug(e.getLocalizedMessage()); + return NfoFileContentType.EXCEPTION; + } + } + + protected abstract NfoFileContentType doCheckNfoFile(Path moviePath, NfoRoot xmlModel) throws IOException; +} diff --git a/src/main/java/drrename/kodi/nfo/NfoContentCoverChecker.java b/src/main/java/drrename/kodi/nfo/NfoContentCoverChecker.java new file mode 100644 index 00000000..74b9d38a --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoContentCoverChecker.java @@ -0,0 +1,48 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.mime.FileTypeByMimeProvider; +import drrename.model.nfo.NfoRoot; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class NfoContentCoverChecker extends NfoContentChecker { + @Override + protected NfoFileContentType doCheckNfoFile(Path moviePath, NfoRoot xmlModel) throws IOException { + if(xmlModel.getMovie().getArt() == null || xmlModel.getMovie().getArt().getPoster() == null){ + return NfoFileContentType.MISSING_POSTER; + } + if(verifyCoverFront(moviePath, xmlModel)){ + return NfoFileContentType.VALID_POSTER; + } + return NfoFileContentType.INVALID_POSTER; + } + + static boolean verifyCoverFront(Path moviePath, NfoRoot xmlFileContent) { + if (xmlFileContent == null || xmlFileContent.getMovie() == null || xmlFileContent.getMovie().getArt() == null || xmlFileContent.getMovie().getArt().getPoster() == null) { + return false; + } + Path coverFront = moviePath.resolve(xmlFileContent.getMovie().getArt().getPoster()); + return Files.isRegularFile(coverFront) && Files.isReadable(coverFront) && new FileTypeByMimeProvider().getFileType(coverFront).startsWith("image"); + } +} diff --git a/src/main/java/drrename/kodi/nfo/NfoContentTitleChecker.java b/src/main/java/drrename/kodi/nfo/NfoContentTitleChecker.java new file mode 100644 index 00000000..c507f34a --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoContentTitleChecker.java @@ -0,0 +1,48 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.Strings; +import drrename.model.nfo.NfoRoot; + +import java.io.IOException; +import java.nio.file.Path; + +public class NfoContentTitleChecker extends NfoContentChecker { + @Override + protected NfoFileContentType doCheckNfoFile(Path moviePath, NfoRoot xmlModel) throws IOException { + if(xmlModel.getMovie().getTitle() == null){ + return NfoFileContentType.MISSING_TITLE; + } + if(verifyTitle(moviePath, xmlModel)){ + return NfoFileContentType.VALID_TITLE; + } + return NfoFileContentType.INVALID_TITLE; + } + + static boolean verifyTitle(Path moviePath, NfoRoot xmlFileContent) { + return xmlFileContent != null && xmlFileContent.getMovie() != null && xmlFileContent.getMovie().getTitle() != null && Strings.startsWithIgnoreCase(moviePath.getFileName().toString(),getSimplifiedName(xmlFileContent.getMovie().getTitle())); + } + + private static String getSimplifiedName(String title) { + // NFO title may be more specific, e.g. might contain punctuation + return title.replaceAll(",", ""); + } +} diff --git a/src/main/java/drrename/kodi/nfo/NfoContentYearChecker.java b/src/main/java/drrename/kodi/nfo/NfoContentYearChecker.java new file mode 100644 index 00000000..8cd0b1a9 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoContentYearChecker.java @@ -0,0 +1,49 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.model.nfo.NfoRoot; + +import java.io.IOException; +import java.nio.file.Path; + +public class NfoContentYearChecker extends NfoContentChecker { + + @Override + protected NfoFileContentType doCheckNfoFile(Path moviePath, NfoRoot xmlModel) throws IOException { + if(xmlModel.getMovie().getYear() == null){ + return NfoFileContentType.MISSING_YEAR; + } + if(verifyYear(moviePath, xmlModel)){ + return NfoFileContentType.VALID_YEAR; + } + return NfoFileContentType.INVALID_YEAR; + } + + private boolean verifyYear(Path moviePath, NfoRoot xmlFileContent) { + return xmlFileContent != null && + xmlFileContent.getMovie() != null && + xmlFileContent.getMovie().getYear() != null && + moviePath.getFileName().toString().endsWith("(" + xmlFileContent.getMovie().getYear() + ")"); + } + + + +} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/SubdirsCheckService.java b/src/main/java/drrename/kodi/nfo/NfoFileCollector.java similarity index 57% rename from src/main/java/drrename/kodi/treeitem/content/check/SubdirsCheckService.java rename to src/main/java/drrename/kodi/nfo/NfoFileCollector.java index 90482ccd..1c64de81 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/SubdirsCheckService.java +++ b/src/main/java/drrename/kodi/nfo/NfoFileCollector.java @@ -17,11 +17,10 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi.nfo; -import drrename.kodi.treeitem.KodiTreeItem; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; +import org.apache.commons.io.FilenameUtils; import java.io.IOException; import java.nio.file.DirectoryStream; @@ -31,30 +30,22 @@ import java.util.List; @Slf4j -@Service -public class SubdirsCheckService extends CheckService { +public class NfoFileCollector { - @Override - public CheckResult checkPath(Path path) throws IOException { - if (getSubdirs(path).isEmpty()) - return new CheckResult("No sub-directories"); - return new CheckResult("Sub-directories found"); - } - - @Override - public KodiTreeItem buildChildItem(CheckResult checkResult) { - return new KodiTreeItem(new CheckResultTreeItemContent(checkResult)); - } - - static List getSubdirs(Path path) throws IOException { - List subdirs = new ArrayList<>(); - try (DirectoryStream ds = Files.newDirectoryStream(path)) { + public List collectNfoFiles(Path directory) throws IOException { + List result = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(directory)) { for (Path child : ds) { - if (Files.isDirectory(child)) { - subdirs.add(child.getFileName()); + String extension = FilenameUtils.getExtension(child.getFileName().toString()); + if(Files.isHidden(child)){ + log.debug("Ignoring hidden NFO file {}", child); + continue; + } + if (Files.isRegularFile(child) && NfoFiles.DEFAULT_EXTENSION.equalsIgnoreCase(extension)) { + result.add(child); } } } - return subdirs; + return result; } } diff --git a/src/main/java/drrename/kodi/nfo/NfoFileContentCoverTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileContentCoverTreeItemValue.java new file mode 100644 index 00000000..4f74ea56 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentCoverTreeItemValue.java @@ -0,0 +1,47 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.model.RenamingPath; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Path; +import java.util.concurrent.Executor; + +@Slf4j +public class NfoFileContentCoverTreeItemValue extends NfoFileContentTreeItemValue { + + public NfoFileContentCoverTreeItemValue(RenamingPath path, Executor executor) { + super(path, false, executor); + } + + @Override + protected String updateIdentifier() { + return "NFO Poster"; + } + + @Override + protected NfoFileContentType parseNfoFile(Path child) { + var checker = new NfoContentCoverChecker(); + var result = checker.checkNfoFile(child); + setNfoFiles(checker.getNfoFiles()); + return result; + } +} diff --git a/src/main/java/drrename/kodi/nfo/NfoFileContentTitleTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileContentTitleTreeItemValue.java new file mode 100644 index 00000000..53816a30 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentTitleTreeItemValue.java @@ -0,0 +1,45 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.model.RenamingPath; + +import java.nio.file.Path; +import java.util.concurrent.Executor; + +public class NfoFileContentTitleTreeItemValue extends NfoFileContentTreeItemValue { + + public NfoFileContentTitleTreeItemValue(RenamingPath moviePath, Executor executor) { + super(moviePath, false, executor); + } + + @Override + protected String updateIdentifier() { + return "NFO Title"; + } + + @Override + protected NfoFileContentType parseNfoFile(Path child) { + var checker = new NfoContentTitleChecker(); + var result = checker.checkNfoFile(child); + setNfoFiles(checker.getNfoFiles()); + return result; + } +} diff --git a/src/main/java/drrename/kodi/nfo/NfoFileContentTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileContentTreeItemValue.java new file mode 100644 index 00000000..f87ac73e --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentTreeItemValue.java @@ -0,0 +1,95 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.model.RenamingPath; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.concurrent.Executor; + +@Slf4j +public abstract class NfoFileContentTreeItemValue extends NfoFileTreeItemValue { + + private final ObjectProperty parseResult; + + public NfoFileContentTreeItemValue(RenamingPath moviePath, boolean fixable, Executor executor) { + super(moviePath, fixable, executor); + this.parseResult = new SimpleObjectProperty<>(); + parseResult.addListener((observable, oldValue, newValue) -> setWarning(newValue.isWarning(isMissingNfoFileIsWarning()))); + missingNfoFileIsWarningProperty().addListener((observable, oldValue, newValue) -> setWarning(getParseResult().isWarning(isMissingNfoFileIsWarning()))); + updateStatus(); + } + + protected NfoFileContentType parseNfoFile() { + + try { + var nfoFiles = new NfoFileCollector().collectNfoFiles(getRenamingPath().getOldPath()); + if (nfoFiles.isEmpty()) { + return NfoFileContentType.NO_FILE; + } + // take a look only at the first file + var result = parseNfoFile(nfoFiles.get(0)); + setNfoFiles(nfoFiles); + return result; + } catch (IOException e) { + log.debug("Failed to parse NFO file. Reason: {}", e.getLocalizedMessage()); + return NfoFileContentType.EXCEPTION; + } + } + + + protected abstract NfoFileContentType parseNfoFile(Path child); + + + @Override + protected void updateStatus() { + parseResult.set(parseNfoFile()); + } + + @Override + protected String updateMessage(Boolean warning) { + return getParseResult().toString(); + } + + @Override + public void fix() { + throw new IllegalStateException("Cannot fix"); + } + + // Getter / Setter // + + public NfoFileContentType getParseResult() { + return parseResult.get(); + } + + public ObjectProperty parseResultProperty() { + return parseResult; + } + + public void setParseResult(NfoFileContentType parseResult) { + this.parseResult.set(parseResult); + } + + +} diff --git a/src/main/java/drrename/kodi/nfo/NfoFileContentType.java b/src/main/java/drrename/kodi/nfo/NfoFileContentType.java new file mode 100644 index 00000000..ff136770 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentType.java @@ -0,0 +1,91 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +public enum NfoFileContentType { + NO_FILE("No file"){ + public boolean isWarning(boolean missingNfoFileIsWarning) { + return missingNfoFileIsWarning; + } + }, + INVALID_FILE("Invalid file"){ + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + } + , INVALID_YEAR("Invalid year"){ + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, VALID_YEAR("Valid year"), + EXCEPTION("Could not parse file"){ + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, URL_ONLY_FILE("URL-only"), + MISSING_YEAR("No year"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, VALID_TITLE("Valid title"), + INVALID_TITLE("Title does not match folder name"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, VALID_POSTER("Valid Poster"), + INVALID_POSTER("Invalid Poster"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, NOT_A_FILE("Not a file"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, MISSING_TITLE("Missing title"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }, MISSING_POSTER("Missing poster"){ + @Override + public boolean isWarning(boolean missingNfoFileIsWarning) { + return true; + } + }; + + private final String name; + + NfoFileContentType(String name){ + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public boolean isWarning(boolean missingNfoFileIsWarning) { + return false; + } +} diff --git a/src/main/java/drrename/kodi/nfo/NfoFileContentUrlTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileContentUrlTreeItemValue.java new file mode 100644 index 00000000..8b4d20a7 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentUrlTreeItemValue.java @@ -0,0 +1,182 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.MovieDbChecker; +import drrename.MovieDbImagesClient; +import drrename.RenameUtil; +import drrename.config.TheMovieDbConfig; +import drrename.kodi.FixFailedException; +import drrename.kodi.KodiTreeItemValue; +import drrename.kodi.KodiUtil; +import drrename.kodi.MovieDbClientFactory; +import drrename.model.RenamingPath; +import javafx.application.Platform; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.*; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +@Slf4j +public class NfoFileContentUrlTreeItemValue extends KodiTreeItemValue { + + @AllArgsConstructor + static + class FixConfig { + Button button; + String newName; + } + + private final ObjectProperty type; + + private final MovieDbChecker checker; + + private final MovieDbImagesClient imagesClient; + + private final TheMovieDbConfig config; + + private FixConfig fixConfig; + + public NfoFileContentUrlTreeItemValue(RenamingPath moviePath, Executor executor, MovieDbClientFactory factory) { + super(moviePath, false, executor); + this.type = new SimpleObjectProperty<>(); + this.checker = factory.getNewMovieDbChecker(); + this.imagesClient = factory.getImagesClient(); + this.config = factory.getConfig(); + updateStatus(); + } + + @Override + protected String updateMessage(Boolean newValue) { + return newValue ? "Movie name could not be found online" + getAdditionalMessageString() : "Movie name found online" + ": " + getType(); + } + + private String getAdditionalMessageString() { + return checker.getOnlineTitles().isEmpty() ? "" : ". Best matches: " + checker.getOnlineTitles().stream().map(Object::toString).collect(Collectors.joining(", ")); + } + + @Override + public void fix() throws FixFailedException { + try { + var renameResult = RenameUtil.rename(getRenamingPath().getOldPath(), fixConfig.newName); + Platform.runLater(() -> getRenamingPath().commitRename(renameResult)); + } catch (IOException e) { + throw new FixFailedException(e); + } + } + + @Override + protected String updateIdentifier() { + return "Movie name lookup"; + } + + + @Override + protected void updateStatus() { + MovieDbCheckType newType = null; + try { + newType = checker.check(KodiUtil.getMovieNameFromDirectoryName(getRenamingPath().getMovieName()), KodiUtil.getMovieYearFromDirectoryName(getRenamingPath().getMovieName())); + } catch (Exception e) { + throw new RuntimeException(e); + } + setType(newType); + setWarning(getType().isWarning()); + updateMessage(isWarning()); + setCanFix(!checker.getOnlineTitles().isEmpty() && isWarning()); + if (!checker.getOnlineTitles().isEmpty() && isWarning()) { + Platform.runLater(() -> setGraphic(buildGraphic2())); + } else { + Platform.runLater(() -> setGraphic(super.buildGraphic())); + } + if (checker.getTheMovieDbId() != null) { + var image = imagesClient.searchMovie(config.getApiKey(), null, true, checker.getTheMovieDbId()); + try { + if (image.getBody() != null) { + Path tempFile = Files.createTempFile("tmp", ".jpg"); + Path outputFile = getRenamingPath().getOldPath().resolve(Paths.get("folder.jpg")); + try (FileOutputStream outputStream = new FileOutputStream(tempFile.toFile())) { + outputStream.write(image.getBody()); + log.debug("Wrote image to {}", tempFile); + } + if (Files.exists(outputFile)) { + FileChannel imageFileChannel = FileChannel.open(outputFile); + long imageFileSize = imageFileChannel.size(); + imageFileChannel.close(); + FileChannel imageFileChannel2 = FileChannel.open(tempFile); + long imageFileSize2 = imageFileChannel2.size(); + imageFileChannel2.close(); + if(imageFileSize2 > imageFileSize){ + log.debug("Downloaded file is larger in size, replacing ours with download"); + Files.move(tempFile, outputFile, StandardCopyOption.REPLACE_EXISTING); + } else { + log.debug("Our image is larger in size, keeping it"); + } + } else { + log.debug("{} does not exist, using download", outputFile); + Files.move(tempFile, outputFile); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private Node buildGraphic2() { + VBox box = new VBox(4); + for (String name : checker.getOnlineTitles()) { + Button button = new Button("Fix to \"" + name + "\""); + VBox.setVgrow(button, Priority.ALWAYS); + button.setMaxWidth(500); + button.setOnAction(event -> button.setOnAction(actionEvent -> { + fixConfig = new FixConfig(button, name); + performFix(); + })); + box.getChildren().add(button); + } + return box; + } + + // FX Getter / Setter // + + + public MovieDbCheckType getType() { + return type.get(); + } + + public ObjectProperty typeProperty() { + return type; + } + + public void setType(MovieDbCheckType type) { + this.type.set(type); + } +} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileContentCheckResult.java b/src/main/java/drrename/kodi/nfo/NfoFileContentYearTreeItemValue.java similarity index 55% rename from src/main/java/drrename/kodi/treeitem/content/check/NfoFileContentCheckResult.java rename to src/main/java/drrename/kodi/nfo/NfoFileContentYearTreeItemValue.java index 587f0d48..72f7bd70 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileContentCheckResult.java +++ b/src/main/java/drrename/kodi/nfo/NfoFileContentYearTreeItemValue.java @@ -17,35 +17,32 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.kodi.nfo; -import java.nio.file.Path; - -public class NfoFileContentCheckResult extends NfoCheckResult { +import drrename.model.RenamingPath; +import lombok.extern.slf4j.Slf4j; - private final Path nfoFile; +import java.nio.file.Path; +import java.util.concurrent.Executor; - private final boolean warning; +@Slf4j +public class NfoFileContentYearTreeItemValue extends NfoFileContentTreeItemValue { - public NfoFileContentCheckResult(String result, Path nfoFile, boolean hasWarning) { - super(result); - this.nfoFile = nfoFile; - this.warning = hasWarning; + public NfoFileContentYearTreeItemValue(RenamingPath path, Executor executor) { + super(path, false, executor); } @Override - public String toString() { -// if(isWarning()){ -// return super.toString() + (nfoFile != null ? " " + nfoFile.getFileName().toString() : ""); -// } - return super.toString(); + protected String updateIdentifier() { + return "NFO Year"; } - public boolean isWarning() { - return warning; - } - public Path getNfoFile() { - return nfoFile; + @Override + protected NfoFileContentType parseNfoFile(Path child) { + var checker = new NfoContentYearChecker(); + var result = checker.checkNfoFile(child); + setNfoFiles(checker.getNfoFiles()); + return result; } } diff --git a/src/main/java/drrename/kodi/nfo/NfoFileNameChecker.java b/src/main/java/drrename/kodi/nfo/NfoFileNameChecker.java new file mode 100644 index 00000000..98e3a296 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileNameChecker.java @@ -0,0 +1,65 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +@Slf4j +public class NfoFileNameChecker extends NfoChecker { + + public NfoFileNameType checkDir(Path directory) { + String movieName = directory.getFileName().toString(); + try { + setNfoFiles(new NfoFileCollector().collectNfoFiles(directory)); + if (getNfoFiles().isEmpty()) { + return NfoFileNameType.NO_FILE; + } + if (getNfoFiles().size() > 1) { + return NfoFileNameType.MULTIPLE_FILES; + } else { + return checkFile(movieName, getNfoFiles().get(0)); + } + } catch (IOException e) { + log.error(e.getLocalizedMessage(), e); + return NfoFileNameType.ERROR; + } + } + + protected NfoFileNameType checkFile(String movieName, Path nfoFile) { + if (!Files.isRegularFile(nfoFile)) { + throw new IllegalArgumentException(nfoFile.getFileName().toString() + " is not a file"); + } + String nfoFileName = nfoFile.getFileName().toString(); + if (NfoFiles.DEFAULT_NAME.equalsIgnoreCase(nfoFileName)) { + return NfoFileNameType.DEFAULT_NAME; + } else if (FilenameUtils.getBaseName(nfoFileName).equalsIgnoreCase(movieName)) { + return NfoFileNameType.MOVIE_NAME; + } else { + return NfoFileNameType.INVALID_NAME; + } + } + + +} diff --git a/src/main/java/drrename/kodi/nfo/NfoFileNameTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileNameTreeItemValue.java new file mode 100644 index 00000000..08bf1ef0 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileNameTreeItemValue.java @@ -0,0 +1,120 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.kodi.FixFailedException; +import drrename.kodi.WarningsConfig; +import drrename.model.RenamingPath; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +@Slf4j +public class NfoFileNameTreeItemValue extends NfoFileTreeItemValue { + + private final ObjectProperty type; + + private final WarningsConfig warningsConfig; + + + public NfoFileNameTreeItemValue(RenamingPath moviePath, WarningsConfig warningsConfig, Executor executor) { + super(moviePath, true, executor); + this.warningsConfig = warningsConfig; + this.type = new SimpleObjectProperty<>(); + updateStatus(); + missingNfoFileIsWarningProperty().addListener((observable, oldValue, newValue) -> setWarning(calculateWarning())); + } + + @Override + protected void updateStatus() { + var checker = new NfoFileNameChecker(); + var type = checker.checkDir(getRenamingPath().getOldPath()); + setNfoFiles(checker.getNfoFiles()); + setType(type); + setWarning(calculateWarning()); + setCanFix(isWarning() && getNfoFiles().size() == 1); + } + + @Override + protected String updateIdentifier() { + return "NFO File Name"; + } + + protected String updateMessage(Boolean newValue) { + if (getType() == null) { + return "unknown"; + } + if (newValue) { + return (getType().toString() + getWarningAdditionalInfo()); + } + return (getType().toString()); + } + + @Override + public void fix() throws FixFailedException { + Path nfoFile = getNfoFile(); + try { + Path newPath = Files.move(nfoFile, nfoFile.resolveSibling(NfoFiles.DEFAULT_NAME)); + if(!newPath.getFileName().toString().equals(NfoFiles.DEFAULT_NAME)){ + throw new FixFailedException("Rename failed"); + } + } catch (IOException e) { + throw new FixFailedException(e); + } + } + + private String getWarningAdditionalInfo() { + return getNfoFiles().isEmpty() ? "" : ": " + getNfoFiles().stream().map(f -> f.getFileName().toString()).collect(Collectors.joining(", ")); + } + + protected boolean calculateWarning() { + if (NfoFileNameType.NO_FILE.equals(getType()) && !isMissingNfoFileIsWarning()) { + return false; + } + return !NfoFileNameType.MOVIE_NAME.equals(getType()) && !NfoFileNameType.DEFAULT_NAME.equals(getType()); + } + + // Getter / Setter // + + + public NfoFileNameType getType() { + return type.get(); + } + + public ObjectProperty typeProperty() { + return type; + } + + public void setType(NfoFileNameType type) { + this.type.set(type); + } + + public WarningsConfig getWarningsConfig() { + return warningsConfig; + } + + +} diff --git a/src/main/java/drrename/kodi/treeitem/content/NfoFileNameType.java b/src/main/java/drrename/kodi/nfo/NfoFileNameType.java similarity index 81% rename from src/main/java/drrename/kodi/treeitem/content/NfoFileNameType.java rename to src/main/java/drrename/kodi/nfo/NfoFileNameType.java index 2a2979b3..519f8b43 100644 --- a/src/main/java/drrename/kodi/treeitem/content/NfoFileNameType.java +++ b/src/main/java/drrename/kodi/nfo/NfoFileNameType.java @@ -17,10 +17,10 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content; +package drrename.kodi.nfo; public enum NfoFileNameType { - NO_FILE("No NFO file"), MOVIE_NAME("NFO file name matching movie name"), DEFAULT_NAME("Default NFO file name"), MULTIPLE_FILES("Multiple NFO files"), INVALID_NAME("Invalid NFO file name"); + NO_FILE("No file"), MOVIE_NAME("File name matching movie name"), DEFAULT_NAME("Default file name"), MULTIPLE_FILES("Multiple files"), INVALID_NAME("Invalid file name"), ERROR("Error"); private final String name; diff --git a/src/main/java/drrename/model/nfo/NfoFileParser.java b/src/main/java/drrename/kodi/nfo/NfoFileParser.java similarity index 71% rename from src/main/java/drrename/model/nfo/NfoFileParser.java rename to src/main/java/drrename/kodi/nfo/NfoFileParser.java index 23668eed..18c026d4 100644 --- a/src/main/java/drrename/model/nfo/NfoFileParser.java +++ b/src/main/java/drrename/kodi/nfo/NfoFileParser.java @@ -17,19 +17,24 @@ * along with this program. If not, see . */ -package drrename.model.nfo; +package drrename.kodi.nfo; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import drrename.model.nfo.NfoRoot; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.stream.Stream; +@Slf4j public class NfoFileParser { private final XmlMapper xmlMapper; @@ -50,9 +55,25 @@ public boolean handleUnknownProperty(DeserializationContext ctxt, JsonParser p, } public NfoRoot parse(Path filePath) throws IOException { - + long lineCount; + try (Stream stream = Files.lines(filePath)) { + lineCount = stream.filter(s -> !s.isBlank()).count(); + }catch (Exception e){ + log.debug("Cannot count lines, reason: {}", e.getLocalizedMessage()); + throw new IOException(e); + } + if(lineCount == 1){ + NfoRoot root = new NfoRoot(); + root.setUrl(Files.readString(filePath)); + return root; + } String content = "" + String.join("", Files.readAllLines(filePath)) + ""; - return xmlMapper.readValue(content, NfoRoot.class); + try { + return xmlMapper.readValue(content, NfoRoot.class); + } catch (MismatchedInputException e) { + log.debug(e.getLocalizedMessage()); + return null; + } } } diff --git a/src/main/java/drrename/kodi/nfo/NfoFileTreeItemValue.java b/src/main/java/drrename/kodi/nfo/NfoFileTreeItemValue.java new file mode 100644 index 00000000..08442044 --- /dev/null +++ b/src/main/java/drrename/kodi/nfo/NfoFileTreeItemValue.java @@ -0,0 +1,74 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.nfo; + +import drrename.kodi.KodiTreeItemValue; +import drrename.model.RenamingPath; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import lombok.Getter; +import lombok.Setter; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Base class for all NFO file related {@code KodiTreeItemValue}s. + * + * @see drrename.kodi.KodiRootTreeItem + */ +@Setter +@Getter +public abstract class NfoFileTreeItemValue extends KodiTreeItemValue { + + private List nfoFiles; + + private BooleanProperty missingNfoFileIsWarning; + + public NfoFileTreeItemValue(RenamingPath moviePath, boolean fixable, Executor executor) { + super(moviePath, fixable, executor); + this.nfoFiles = new ArrayList<>(); + this.missingNfoFileIsWarning = new SimpleBooleanProperty(); + } + + @Override + public String toString() { + return super.toString(); + } + + public Path getNfoFile() { + return nfoFiles.isEmpty() ? null : nfoFiles.get(0); + } + + public boolean isMissingNfoFileIsWarning() { + return missingNfoFileIsWarning.get(); + } + + public BooleanProperty missingNfoFileIsWarningProperty() { + return missingNfoFileIsWarning; + } + + public void setMissingNfoFileIsWarning(boolean missingNfoFileIsWarning) { + this.missingNfoFileIsWarning.set(missingNfoFileIsWarning); + } +} + diff --git a/src/main/java/drrename/kodi/treeitem/NfoFileNameTreeItem.java b/src/main/java/drrename/kodi/nfo/NfoFiles.java similarity index 76% rename from src/main/java/drrename/kodi/treeitem/NfoFileNameTreeItem.java rename to src/main/java/drrename/kodi/nfo/NfoFiles.java index 58416b65..9374ac90 100644 --- a/src/main/java/drrename/kodi/treeitem/NfoFileNameTreeItem.java +++ b/src/main/java/drrename/kodi/nfo/NfoFiles.java @@ -17,13 +17,12 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem; +package drrename.kodi.nfo; -import drrename.kodi.treeitem.content.NfoFileNameTreeItemContent; +public class NfoFiles { -public class NfoFileNameTreeItem extends KodiTreeItem { + public static final String DEFAULT_EXTENSION = "nfo"; + + public static final String DEFAULT_NAME = "movie" + "." + DEFAULT_EXTENSION; - public NfoFileNameTreeItem(NfoFileNameTreeItemContent value) { - super(value); - } } diff --git a/src/main/java/drrename/kodi/treeitem/content/NfoFileContentCheckService.java b/src/main/java/drrename/kodi/treeitem/content/NfoFileContentCheckService.java deleted file mode 100644 index b7e275f8..00000000 --- a/src/main/java/drrename/kodi/treeitem/content/NfoFileContentCheckService.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Dr.Rename - A Minimalistic Batch Renamer - * - * Copyright (C) 2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package drrename.kodi.treeitem.content; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import drrename.kodi.treeitem.KodiTreeItem; -import drrename.kodi.treeitem.content.check.CheckService; -import drrename.kodi.treeitem.content.check.NfoFileContentCheckResult; -import drrename.model.nfo.NfoFileXmlModel; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FilenameUtils; - -import java.io.IOException; -import java.nio.charset.MalformedInputException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; - -@RequiredArgsConstructor -@Slf4j -public class NfoFileContentCheckService extends CheckService { - - @Override - public KodiTreeItem buildChildItem(NfoFileContentCheckResult checkResult) { - return new KodiTreeItem(new NfoFileContentTreeItemContent(checkResult)); - } - - public NfoFileContentCheckResult checkPath(Path path) throws IOException { - XmlMapper mapper = new XmlMapper(); - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - - try (DirectoryStream ds = Files.newDirectoryStream(path)) { - for (Path child : ds) { - String extension = FilenameUtils.getExtension(child.getFileName().toString()); - if (Files.isRegularFile(child) && "nfo".equalsIgnoreCase(extension)) { - // we look only at the first file found - try { - NfoFileXmlModel xmlFileContent = mapper.readValue(child.toFile(), NfoFileXmlModel.class); - if (!verifyTitle(path, xmlFileContent)) { - return new NfoFileContentCheckResult("NFO title mismatch", child, true); - } - if (!verifyYear(path, xmlFileContent)) { - return new NfoFileContentCheckResult("NFO year mismatch", child, true); - } - if (!verifyCoverFront(path, xmlFileContent)) { - return new NfoFileContentCheckResult("NFO front-cover not readable", child, true); - } - return new NfoFileContentCheckResult("XML NFO", child, false); - } catch (JsonParseException e) { - log.debug("{} for {}", e.getLocalizedMessage(), child); - try { - String content = Files.readString(child); - if (content == null) { - return new NfoFileContentCheckResult("Empty NFO", child, true); - } - if (content.contains("imdb")) { - return new NfoFileContentCheckResult("Single line NFO (imdb)", child, false); - } else { - return new NfoFileContentCheckResult("Unknown NFO content", child, true); - } - } catch (MalformedInputException ee) { - log.debug("{} for {}", ee.getLocalizedMessage(), child); - log.debug("{} for path {}", ee.getLocalizedMessage(), path); - return new NfoFileContentCheckResult("Invalid NFO content", child, true); - } - } - } - } - return new NfoFileContentCheckResult("No NFO file", null, true); - } - } - - - private boolean verifyYear(Path moviePath, NfoFileXmlModel xmlFileContent) { - return xmlFileContent.getYear() != null && moviePath.getFileName().toString().endsWith("(" + xmlFileContent.getYear() + ")"); - } - - private boolean verifyTitle(Path moviePath, NfoFileXmlModel xmlFileContent) { - return xmlFileContent.getTitle() != null && moviePath.getFileName().toString().startsWith(xmlFileContent.getTitle()); - } - - private boolean verifyCoverFront(Path moviePath, NfoFileXmlModel xmlFileContent) { - if (xmlFileContent.getArt() == null || xmlFileContent.getArt().getPoster() == null) { - return false; - } - Path coverFront = moviePath.resolve(xmlFileContent.getArt().getPoster()); - return Files.isRegularFile(coverFront) && Files.isReadable(coverFront); - } -} diff --git a/src/main/java/drrename/kodi/treeitem/content/NfoFileNameTreeItemContent.java b/src/main/java/drrename/kodi/treeitem/content/NfoFileNameTreeItemContent.java deleted file mode 100644 index 4c456b77..00000000 --- a/src/main/java/drrename/kodi/treeitem/content/NfoFileNameTreeItemContent.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Dr.Rename - A Minimalistic Batch Renamer - * - * Copyright (C) 2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package drrename.kodi.treeitem.content; - -import drrename.kodi.treeitem.content.check.NfoFileNameCheckResult; -import drrename.kodi.treeitem.content.check.NfoCheckResultTreeItemContent; - -import java.util.stream.Collectors; - -public class NfoFileNameTreeItemContent extends NfoCheckResultTreeItemContent { - - public NfoFileNameTreeItemContent(NfoFileNameCheckResult checkResult) { - super(checkResult); - } - - @Override - public boolean hasWarning() { - if(NfoFileNameType.NO_FILE.equals(getCheckResult().getType()) && !isMissingNfoIsAWarning()){ - return false; - } - return !NfoFileNameType.MOVIE_NAME.equals(getCheckResult().getType()) && !NfoFileNameType.DEFAULT_NAME.equals(getCheckResult().getType()); - } - - @Override - public String toString() { - if(hasWarning()){ - return super.toString() + " " + getCheckResult().getNfoFiles().stream().map(e -> e.getFileName().toString()).collect(Collectors.joining(", ")); - } - return super.toString(); - } -} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/CheckResult.java b/src/main/java/drrename/kodi/treeitem/content/check/CheckResult.java deleted file mode 100644 index 99d80ca7..00000000 --- a/src/main/java/drrename/kodi/treeitem/content/check/CheckResult.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Dr.Rename - A Minimalistic Batch Renamer - * - * Copyright (C) 2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package drrename.kodi.treeitem.content.check; - -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; - -import java.util.Objects; - -public class CheckResult { - - protected final StringProperty result; - - public CheckResult(String result) { - this.result = new SimpleStringProperty(result); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CheckResult that)) return false; - return Objects.equals(getResult(), that.getResult()); - } - - @Override - public int hashCode() { - return Objects.hash(result); - } - - @Override - public String toString() { - return getResult(); - } - - // Getter / Setter // - - public String getResult() { - return result.get(); - } - - public StringProperty resultProperty() { - return result; - } - - public void setResult(String result) { - this.result.set(result); - } - - -} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckResult.java b/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckResult.java deleted file mode 100644 index 9a8cd6a5..00000000 --- a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckResult.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Dr.Rename - A Minimalistic Batch Renamer - * - * Copyright (C) 2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package drrename.kodi.treeitem.content.check; - -import drrename.kodi.treeitem.content.NfoFileNameType; -import javafx.beans.property.ListProperty; -import javafx.beans.property.SimpleListProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import java.nio.file.Path; -import java.util.Collection; - -public class NfoFileNameCheckResult extends NfoCheckResult { - - private final ListProperty nfoFiles; - private final NfoFileNameType type; - - public NfoFileNameCheckResult(NfoFileNameType result, Collection nfoFiles) { - super(result.toString()); - this.type = result; - this.nfoFiles = new SimpleListProperty<>(FXCollections.observableArrayList(nfoFiles)); - } - - @Override - public Path getNfoFile() { - return getNfoFiles().isEmpty() ? null : getNfoFiles().get(0); - } - - // Getter / Setter // - - public NfoFileNameType getType() { - return type; - } - - public ObservableList getNfoFiles() { - return nfoFiles.get(); - } - - public ListProperty nfoFilesProperty() { - return nfoFiles; - } - - public void setNfoFiles(ObservableList nfoFiles) { - this.nfoFiles.set(nfoFiles); - } - - -} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckService.java b/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckService.java deleted file mode 100644 index 0ed1ca0a..00000000 --- a/src/main/java/drrename/kodi/treeitem/content/check/NfoFileNameCheckService.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Dr.Rename - A Minimalistic Batch Renamer - * - * Copyright (C) 2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package drrename.kodi.treeitem.content.check; - -import drrename.kodi.treeitem.NfoFileNameTreeItem; -import drrename.kodi.treeitem.content.NfoFileNameType; -import drrename.kodi.treeitem.content.NfoFileNameTreeItemContent; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FilenameUtils; - -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -@Slf4j -public class NfoFileNameCheckService extends CheckService { - - @Override - public NfoFileNameTreeItem buildChildItem(NfoFileNameCheckResult checkResult) { - return new NfoFileNameTreeItem(new NfoFileNameTreeItemContent(checkResult)); - } - - @Override - public NfoFileNameCheckResult checkPath(Path path) throws IOException { - if(!Files.isDirectory(path)){ - throw new IllegalArgumentException(path.getFileName().toString() + " is not a directory"); - } - String movieName = path.getFileName().toString(); - List childString = new ArrayList<>(); - NfoFileNameType type = NfoFileNameType.NO_FILE; - try (DirectoryStream ds = Files.newDirectoryStream(path)) { - for (Path child : ds) { - String extension = FilenameUtils.getExtension(child.getFileName().toString()); - if (Files.isRegularFile(child) && "nfo".equalsIgnoreCase(extension)) { - childString.add(child); - if(childString.size() > 1){ - type = NfoFileNameType.MULTIPLE_FILES; - } else { - type = checkFile(movieName, child); - } - } - } - } - return new NfoFileNameCheckResult(type, childString); - } - - static NfoFileNameType checkFile(String movieName, Path child) { - if(!Files.isRegularFile(child)){ - throw new IllegalArgumentException(child.getFileName().toString() + " is not a directory"); - } - String childName = child.getFileName().toString(); - if ("movie.nfo".equalsIgnoreCase(childName)) { - return NfoFileNameType.DEFAULT_NAME; - } else if (FilenameUtils.getBaseName(childName).equalsIgnoreCase(movieName)) { - return NfoFileNameType.MOVIE_NAME; - } else { - return NfoFileNameType.INVALID_NAME; - } - } - - -} diff --git a/src/main/java/drrename/kodi/treeitem/content/check/CheckService.java b/src/main/java/drrename/mime/FileTypeByMimeProvider.java similarity index 57% rename from src/main/java/drrename/kodi/treeitem/content/check/CheckService.java rename to src/main/java/drrename/mime/FileTypeByMimeProvider.java index 10cff9cd..e39fe0f4 100644 --- a/src/main/java/drrename/kodi/treeitem/content/check/CheckService.java +++ b/src/main/java/drrename/mime/FileTypeByMimeProvider.java @@ -17,31 +17,37 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem.content.check; +package drrename.mime; -import drrename.kodi.treeitem.KodiTreeItem; -import drrename.kodi.treeitem.MovieTreeItem; -import javafx.application.Platform; +import drrename.FileTypeProvider; import lombok.extern.slf4j.Slf4j; +import org.apache.tika.Tika; -import java.io.IOException; +import java.io.File; +import java.nio.file.Files; import java.nio.file.Path; @Slf4j -public abstract class CheckService { +public class FileTypeByMimeProvider implements FileTypeProvider { - public void addChildItem(MovieTreeItem treeItem) { + public static String UNKNOWN = "n/a"; + + public static String DIRECTORY = "directory"; + + @Override + public String getFileType(Path path) { + final File file = path.toFile(); + if(Files.isDirectory(path)){ + return DIRECTORY; + } try { - R checkResult = checkPath(treeItem.getMoviePath()); - var childItem = buildChildItem(checkResult); - if(!treeItem.contains(childItem)) - Platform.runLater(() -> treeItem.add(childItem)); - }catch (IOException e){ + Tika tika = new Tika(); + @SuppressWarnings("") + var result = tika.detect(file); + return result; + } catch (Exception e) { log.error(e.getLocalizedMessage(), e); + return UNKNOWN; } } - - public abstract R checkPath(Path path) throws IOException; - - public abstract KodiTreeItem buildChildItem(R checkResult); } diff --git a/src/main/java/drrename/model/RenamingControl.java b/src/main/java/drrename/model/RenamingControl.java new file mode 100644 index 00000000..91cbd14e --- /dev/null +++ b/src/main/java/drrename/model/RenamingControl.java @@ -0,0 +1,120 @@ +package drrename.model; + +import drrename.ui.Styles; +import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.value.ObservableValue; +import javafx.geometry.Insets; +import javafx.scene.control.Control; +import javafx.scene.control.Label; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Path; +import java.util.concurrent.Callable; + +@Slf4j +public class RenamingControl extends RenamingPath { + + private final StringProperty fileType; + + private final Control leftControl; + + private final Control rightControl; + + public RenamingControl(final Path path) { + super(path); + + this.fileType = new SimpleStringProperty(); + newPath.addListener((v, o, n) -> willChange.set(!getOldPath().getFileName().toString().equals(n))); + oldPath.addListener((observable, oldValue, newValue) -> willChange.set(!getOldPath().getFileName().toString().equals(getNewPath()))); + leftControl = buildLeft(); + rightControl = buildRight(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{" + getOldPath().toString() + "}"; + } + + protected Control buildLeft() { + + final Label tLeft = new Label(); + tLeft.setPadding(new Insets(2, 2, 2, 2)); + tLeft.textProperty().bind(buildTextBindingLeft()); + tLeft.styleProperty().bind(buildStyleBindingLeft()); + + return tLeft; + } + + protected ObservableValue buildStyleBindingLeft() { + return Bindings.createObjectBinding(this::calcStyleLeft); + } + + protected ObservableValue buildTextBindingLeft() { + return Bindings.createObjectBinding(this::calculateOldPath, oldPathProperty()); + } + + protected String calculateOldPath() { + return getOldPath().getFileName().toString(); + } + + protected String calcStyleLeft() { + final StringBuilder sb = new StringBuilder(); + if (getOldPath().toFile().isDirectory()) { + sb.append(Styles.directoryStyle()); + } + if (sb.toString().length() > 0) + return sb.toString(); + return Styles.defaultStyle(); + } + + protected Control buildRight() { + + final Label tRight = new Label(); + tRight.setPadding(new Insets(2, 2, 2, 2)); + tRight.setMaxWidth(Double.POSITIVE_INFINITY); + tRight.textProperty().bind(Bindings.createStringBinding(buildTextRight(), exceptionProperty(), newPathProperty())); + tRight.styleProperty().bind( + Bindings.createObjectBinding(this::calcStyleRight, willChangeProperty(), exceptionProperty(), newPathProperty())); + return tRight; + } + + protected Callable buildTextRight() { + return () -> { + if (getException() != null) + return getException().toString(); + return getNewPath() == null ? null : getNewPath(); + }; + } + + protected String calcStyleRight() { + if (isWillChange()) { + return Styles.changingStyle(); + } + return Styles.defaultStyle(); + } + + // Getter / Setter // + + + public StringProperty fileTypeProperty() { + return fileType; + } + + public String getFileType() { + return fileType.get(); + } + + public void setFileType(String fileType) { + fileTypeProperty().set(fileType); + } + + public Control getLeftControl() { + return leftControl; + } + + public Control getRightControl() { + return rightControl; + } +} diff --git a/src/main/java/drrename/model/RenamingEntry.java b/src/main/java/drrename/model/RenamingEntry.java deleted file mode 100644 index eda840e6..00000000 --- a/src/main/java/drrename/model/RenamingEntry.java +++ /dev/null @@ -1,224 +0,0 @@ -package drrename.model; - -import drrename.strategy.RenamingStrategy; -import drrename.ui.Styles; -import javafx.application.Platform; -import javafx.beans.binding.Bindings; -import javafx.beans.property.*; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Insets; -import javafx.scene.control.Control; -import javafx.scene.control.Label; -import lombok.extern.slf4j.Slf4j; - -import java.io.FileNotFoundException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.concurrent.Callable; - -@Slf4j -public class RenamingEntry { - - private final ObjectProperty oldPath; - private final StringProperty newPath; - private final ObjectProperty exception; - private final BooleanProperty willChange; - private final BooleanProperty filtered; - private final StringProperty fileType; - - private final Control leftControl; - - private final Control rightControl; - - public RenamingEntry(final Path path) { - - this.oldPath = new SimpleObjectProperty<>(Objects.requireNonNull(path)); - this.newPath = new SimpleStringProperty(); - exception = new SimpleObjectProperty<>(); - this.willChange = new SimpleBooleanProperty(); - this.fileType = new SimpleStringProperty(); - this.filtered = new SimpleBooleanProperty(); - newPath.addListener((v, o, n) -> willChange.set(!getOldPath().getFileName().toString().equals(n))); - oldPath.addListener((observable, oldValue, newValue) -> willChange.set(!getOldPath().getFileName().toString().equals(getNewPath()))); - leftControl = buildLeft(); - rightControl = buildRight(); - } - - public String preview(final RenamingStrategy strategy) { - - if (Files.exists(getOldPath())) { - final String s = strategy.getNameNew(getOldPath()); - Platform.runLater(() -> newPath.set(s)); - return s; - } - var exception = new FileNotFoundException(getOldPath().getFileName().toString()); - Platform.runLater(() -> exceptionProperty().set(exception)); - return null; - } - - public Path rename(final RenamingStrategy strategy) { - if (isFiltered()) { - log.warn("Rename called on filtered entry, skipping {}", this); - return getOldPath(); - } - try { - Path newPath = strategy.rename(getOldPath(), null); - Platform.runLater(() -> commitRename(newPath)); - return newPath; - } catch (final Exception e) { - log.debug(e.getLocalizedMessage(), e); - Platform.runLater(() -> this.exception.set(e)); - return getOldPath(); - } - } - - public void commitRename(Path newPath) { - setOldPath(newPath); - exceptionProperty().set(null); - // for now set to false to see an immediate effect, preview service should be triggered and should update this any time soon again. - setWillChange(false); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{" + getOldPath().toString() + "}"; - } - - protected Control buildLeft() { - - final Label tLeft = new Label(); - tLeft.setPadding(new Insets(2, 2, 2, 2)); - tLeft.textProperty().bind(buildTextBindingLeft()); - tLeft.styleProperty().bind(buildStyleBindingLeft()); - - return tLeft; - } - - protected ObservableValue buildStyleBindingLeft() { - return Bindings.createObjectBinding(this::calcStyleLeft); - } - - protected ObservableValue buildTextBindingLeft() { - return Bindings.createObjectBinding(this::calculateOldPath, oldPathProperty()); - } - - protected String calculateOldPath() { - return getOldPath().getFileName().toString(); - } - - protected String calcStyleLeft() { - final StringBuilder sb = new StringBuilder(); - if (getOldPath().toFile().isDirectory()) { - sb.append(Styles.directoryStyle()); - } - if (sb.toString().length() > 0) - return sb.toString(); - return Styles.defaultStyle(); - } - - protected Control buildRight() { - - final Label tRight = new Label(); - tRight.setPadding(new Insets(2, 2, 2, 2)); - tRight.setMaxWidth(Double.POSITIVE_INFINITY); - tRight.textProperty().bind(Bindings.createStringBinding(buildTextRight(), exceptionProperty(), newPathProperty())); - tRight.styleProperty().bind( - Bindings.createObjectBinding(this::calcStyleRight, willChangeProperty(), exceptionProperty(), newPathProperty())); - return tRight; - } - - protected Callable buildTextRight() { - return () -> { - if (getException() != null) - return getException().toString(); - return getNewPath() == null ? null : getNewPath(); - }; - } - - protected String calcStyleRight() { - if (willChange()) { - return Styles.changingStyle(); - } - return Styles.defaultStyle(); - } - - // Getter / Setter // - - - public BooleanProperty filteredProperty() { - return filtered; - } - - public boolean isFiltered() { - return filtered.get(); - } - - public void setFiltered(boolean filtered) { - this.filtered.set(filtered); - } - - public StringProperty fileTypeProperty() { - return fileType; - } - - public String getFileType() { - return fileType.get(); - } - - public void setFileType(String fileType) { - fileTypeProperty().set(fileType); - } - - public void setNewPath(String newPath) { - this.newPath.set(newPath); - } - - public String getNewPath() { - return newPath.get(); - } - - public Throwable getException() { - return exception.get(); - } - - public ObjectProperty exceptionProperty() { - return exception; - } - - public StringProperty newPathProperty() { - return newPath; - } - - public BooleanProperty willChangeProperty() { - return this.willChange; - } - - public boolean willChange() { - return this.willChangeProperty().get(); - } - - public void setWillChange(final boolean willChange) { - this.willChangeProperty().set(willChange); - } - - public ObjectProperty oldPathProperty() { - return this.oldPath; - } - - public Path getOldPath() { - return this.oldPathProperty().get(); - } - - public void setOldPath(final Path oldPath) { - this.oldPathProperty().set(oldPath); - } - - public Control getLeftControl() { - return leftControl; - } - - public Control getRightControl() { - return rightControl; - } -} diff --git a/src/main/java/drrename/model/RenamingPath.java b/src/main/java/drrename/model/RenamingPath.java new file mode 100644 index 00000000..e8a9dde0 --- /dev/null +++ b/src/main/java/drrename/model/RenamingPath.java @@ -0,0 +1,175 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.model; + +import drrename.strategy.RenamingStrategy; +import javafx.application.Platform; +import javafx.beans.property.*; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileNotFoundException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +@Slf4j +public class RenamingPath { + protected final ObjectProperty oldPath; + + protected final StringProperty newPath; + + protected final ObjectProperty exception; + + protected final BooleanProperty willChange; + + protected final BooleanProperty filtered; + + protected final StringProperty movieName; + private final ChangeListener listener; + + public RenamingPath(final Path path) { + listener = new ChangeListener() { + @Override + public void changed(ObservableValue observableValue, Path path, Path t1) { + movieName.set(t1.getFileName().toString()); + } + }; + this.oldPath = new SimpleObjectProperty<>(); + this.newPath = new SimpleStringProperty(); + this.movieName = new SimpleStringProperty(); + this.exception = new SimpleObjectProperty<>(); + this.willChange = new SimpleBooleanProperty(); + this.filtered = new SimpleBooleanProperty(); + oldPath.addListener(listener); + oldPath.set(Objects.requireNonNull(path)); + } + + public String preview(final RenamingStrategy strategy) { + + if (Files.exists(getOldPath())) { + final String s = strategy.getNameNew(getOldPath()); + Platform.runLater(() -> newPath.set(s)); + return s; + } + var exception = new FileNotFoundException(getOldPath().getFileName().toString()); + Platform.runLater(() -> exceptionProperty().set(exception)); + return null; + } + + public Path rename(final RenamingStrategy strategy) { + if (isFiltered()) { + log.warn("Rename called on filtered entry, skipping {}", this); + return getOldPath(); + } + try { + Path newPath = strategy.rename(getOldPath(), null); + Platform.runLater(() -> commitRename(newPath)); + return newPath; + } catch (final Exception e) { + log.debug(e.getLocalizedMessage(), e); + Platform.runLater(() -> this.exception.set(e)); + return getOldPath(); + } + } + + public void commitRename(Path newPath) { + setOldPath(newPath); + exceptionProperty().set(null); + // for now set to false to see an immediate effect, preview service should be triggered and should update this any time soon again. + setWillChange(false); + } + + // Getter / Setter // + + + public String getMovieName() { + return movieName.get(); + } + + public StringProperty movieNameProperty() { + return movieName; + } + + public void setMovieName(String movieName) { + this.movieName.set(movieName); + } + + public Path getOldPath() { + return oldPath.get(); + } + + public void setOldPath(Path oldPath) { + this.oldPath.set(oldPath); + } + + public String getNewPath() { + return newPath.get(); + } + + public void setNewPath(String newPath) { + this.newPath.set(newPath); + } + + public Throwable getException() { + return exception.get(); + } + + public void setException(Throwable exception) { + this.exception.set(exception); + } + + public boolean isWillChange() { + return willChange.get(); + } + + public void setWillChange(boolean willChange) { + this.willChange.set(willChange); + } + + public boolean isFiltered() { + return filtered.get(); + } + + public void setFiltered(boolean filtered) { + this.filtered.set(filtered); + } + + public BooleanProperty filteredProperty() { + return filtered; + } + + public ObjectProperty exceptionProperty() { + return exception; + } + + public StringProperty newPathProperty() { + return newPath; + } + + public BooleanProperty willChangeProperty() { + return this.willChange; + } + + public ObjectProperty oldPathProperty() { + return this.oldPath; + } +} diff --git a/src/main/java/drrename/kodi/treeitem/MovieTreeItem.java b/src/main/java/drrename/model/themoviedb/SearchResultDto.java similarity index 63% rename from src/main/java/drrename/kodi/treeitem/MovieTreeItem.java rename to src/main/java/drrename/model/themoviedb/SearchResultDto.java index 2ff6503e..27de1a36 100644 --- a/src/main/java/drrename/kodi/treeitem/MovieTreeItem.java +++ b/src/main/java/drrename/model/themoviedb/SearchResultDto.java @@ -17,23 +17,30 @@ * along with this program. If not, see . */ -package drrename.kodi.treeitem; +package drrename.model.themoviedb; -import drrename.kodi.treeitem.content.MovieTreeItemContent; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; -import java.nio.file.Path; +import java.time.LocalDate; -public class MovieTreeItem extends KodiTreeItem { +@Data +public class SearchResultDto { - public MovieTreeItem(MovieTreeItemContent content) { - super(content); - } + @JsonProperty("original_title") + String originalTitle; - public MovieTreeItem(Path moviePath) { - this(new MovieTreeItemContent(moviePath)); - } + @JsonProperty("title") + String title; - public Path getMoviePath(){ - return ((MovieTreeItemContent)getValue()).getMoviePath(); - } + @JsonProperty("overview") + String overview; + + Number id; + + @JsonProperty("release_date") + LocalDate releaseDate; + + @JsonProperty("poster_path") + String posterPath; } diff --git a/src/main/java/drrename/model/themoviedb/SearchResultsDto.java b/src/main/java/drrename/model/themoviedb/SearchResultsDto.java new file mode 100644 index 00000000..2ad7c33a --- /dev/null +++ b/src/main/java/drrename/model/themoviedb/SearchResultsDto.java @@ -0,0 +1,30 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.model.themoviedb; + +import lombok.Data; + +import java.util.List; + +@Data +public class SearchResultsDto { + + List results; +} diff --git a/src/main/java/drrename/model/themoviedb/TranslationData.java b/src/main/java/drrename/model/themoviedb/TranslationData.java new file mode 100644 index 00000000..46a216d3 --- /dev/null +++ b/src/main/java/drrename/model/themoviedb/TranslationData.java @@ -0,0 +1,28 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.model.themoviedb; + +import lombok.Data; + +@Data +public class TranslationData { + + String title; +} diff --git a/src/main/java/drrename/model/themoviedb/TranslationDto.java b/src/main/java/drrename/model/themoviedb/TranslationDto.java new file mode 100644 index 00000000..b892bf57 --- /dev/null +++ b/src/main/java/drrename/model/themoviedb/TranslationDto.java @@ -0,0 +1,35 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.model.themoviedb; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class TranslationDto { + + @JsonProperty("iso_3166_1") + String iso3166; + + @JsonProperty("iso_639_1") + String iso639; + + TranslationData data; +} diff --git a/src/main/java/drrename/model/themoviedb/TranslationsDto.java b/src/main/java/drrename/model/themoviedb/TranslationsDto.java new file mode 100644 index 00000000..9bcf6a7c --- /dev/null +++ b/src/main/java/drrename/model/themoviedb/TranslationsDto.java @@ -0,0 +1,31 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.model.themoviedb; + +import lombok.Data; + +import java.util.List; + +@Data +public class TranslationsDto { + + List translations; + +} diff --git a/src/main/java/drrename/service/EntriesService.java b/src/main/java/drrename/service/EntriesService.java index 54885385..e16855f4 100644 --- a/src/main/java/drrename/service/EntriesService.java +++ b/src/main/java/drrename/service/EntriesService.java @@ -3,7 +3,7 @@ import drrename.config.AppConfig; import drrename.event.FileRenamedEvent; import drrename.event.NewRenamingEntryEvent; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.property.*; @@ -44,25 +44,25 @@ public class EntriesService { private final AppConfig appConfig; - private final ListProperty entries; + private final ListProperty entries; - private final ListProperty entriesFiltered; + private final ListProperty entriesFiltered; - private final FilteredList entriesWillRename; + private final FilteredList entriesWillRename; - private final FilteredList loadedImageEntries; + private final FilteredList loadedImageEntries; - private final FilteredList loadedVideosEntries; + private final FilteredList loadedVideosEntries; - private final FilteredList willRenameImageEntries; + private final FilteredList willRenameImageEntries; - private final FilteredList willRenameVideosEntries; + private final FilteredList willRenameVideosEntries; - private final ListProperty entriesRenamed; + private final ListProperty entriesRenamed; - private final FilteredList renamedImageEntries; + private final FilteredList renamedImageEntries; - private final FilteredList renamedVideosEntries; + private final FilteredList renamedVideosEntries; private final StringProperty statusLoaded = new SimpleStringProperty(); @@ -82,13 +82,13 @@ public class EntriesService { private final BooleanProperty showOnlyChainging = new SimpleBooleanProperty(); - private final Predicate entriesFilteredDefaultPredicate = e -> true; + private final Predicate entriesFilteredDefaultPredicate = e -> true; - private final static Predicate isImage = e -> e.getFileType() != null && e.getFileType().contains("image"); + private final static Predicate isImage = e -> e.getFileType() != null && e.getFileType().contains("image"); - private final static Predicate isVideo = e -> e.getFileType() != null && e.getFileType().contains("video"); + private final static Predicate isVideo = e -> e.getFileType() != null && e.getFileType().contains("video"); - private final static Predicate noHidden = e -> { + private final static Predicate noHidden = e -> { try { return !Files.isHidden(e.getOldPath()); } catch (IOException ex) { @@ -98,9 +98,9 @@ public class EntriesService { } }; - private final static Predicate noDirectories = e -> !Files.isDirectory(e.getOldPath()); + private final static Predicate noDirectories = e -> !Files.isDirectory(e.getOldPath()); - private final static Predicate onlyChanging = RenamingEntry::willChange; + private final static Predicate onlyChanging = RenamingControl::isWillChange; public EntriesService(ResourceBundle resourceBundle, AppConfig appConfig, Executor executor) { this.resourceBundle = resourceBundle; @@ -108,7 +108,7 @@ public EntriesService(ResourceBundle resourceBundle, AppConfig appConfig, Execut entries = new SimpleListProperty<>(FXCollections.observableArrayList(item -> new Observable[]{item.newPathProperty(), item.exceptionProperty(), item.fileTypeProperty(), item.filteredProperty(), item.willChangeProperty()})); entriesFiltered = new SimpleListProperty<>(new FilteredList<>(entries, entriesFilteredDefaultPredicate)); entriesRenamed = new SimpleListProperty<>(FXCollections.observableArrayList()); - entriesWillRename = new FilteredList<>(entries, RenamingEntry::willChange); + entriesWillRename = new FilteredList<>(entries, RenamingControl::isWillChange); loadedImageEntries = new FilteredList<>(entries, isImage); loadedVideosEntries = new FilteredList<>(entries, isVideo); willRenameImageEntries = new FilteredList<>(entriesWillRename, isImage); @@ -130,29 +130,29 @@ private void initListeners() { entries.sizeProperty().addListener((observable, oldValue, newValue) -> statusLoaded.setValue(String.format(resourceBundle.getString(LOADED), newValue))); - entriesWillRename.addListener((ListChangeListener) c -> statusWillRename.setValue(String.format(resourceBundle.getString(WILL_RENAME), c.getList().size()))); + entriesWillRename.addListener((ListChangeListener) c -> statusWillRename.setValue(String.format(resourceBundle.getString(WILL_RENAME), c.getList().size()))); entriesRenamed.sizeProperty().addListener((observable, oldValue, newValue) -> statusRenamed.setValue(String.format(resourceBundle.getString(RENAMED), newValue))); - loadedImageEntries.addListener((ListChangeListener) c -> updateLoadedFileTypesLabel()); + loadedImageEntries.addListener((ListChangeListener) c -> updateLoadedFileTypesLabel()); - loadedVideosEntries.addListener((ListChangeListener) c -> updateLoadedFileTypesLabel()); + loadedVideosEntries.addListener((ListChangeListener) c -> updateLoadedFileTypesLabel()); - willRenameImageEntries.addListener((ListChangeListener) c -> updateWillRenameFileTypesLabel()); + willRenameImageEntries.addListener((ListChangeListener) c -> updateWillRenameFileTypesLabel()); - willRenameVideosEntries.addListener((ListChangeListener) c -> updateWillRenameFileTypesLabel()); + willRenameVideosEntries.addListener((ListChangeListener) c -> updateWillRenameFileTypesLabel()); - renamedImageEntries.addListener((ListChangeListener) c -> updateRenamedFileTypesLabel()); + renamedImageEntries.addListener((ListChangeListener) c -> updateRenamedFileTypesLabel()); - renamedVideosEntries.addListener((ListChangeListener) c -> updateRenamedFileTypesLabel()); + renamedVideosEntries.addListener((ListChangeListener) c -> updateRenamedFileTypesLabel()); - filterHiddenFiles.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); - filterDirectories.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); - showOnlyChainging.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); + filterHiddenFiles.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); + filterDirectories.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); + showOnlyChainging.addListener((observable, oldValue, newValue) -> ((FilteredList)entriesFiltered.get()).setPredicate(getCombinedPredicate())); } - private Predicate getCombinedPredicate() { - Predicate resultPredicate = null; + private Predicate getCombinedPredicate() { + Predicate resultPredicate = null; if(isFilterHiddenFiles()){ resultPredicate = noHidden; } @@ -191,7 +191,7 @@ public void onFileRenamedEvent(FileRenamedEvent event) { // Getter / Setter - public ObservableList getEntries() { + public ObservableList getEntries() { return entries.get(); } @@ -255,8 +255,8 @@ public void setFilterHiddenFiles(boolean filterHiddenFiles) { this.filterHiddenFiles.set(filterHiddenFiles); } - public FilteredList getEntriesFiltered() { - return (FilteredList) entriesFiltered.get(); + public FilteredList getEntriesFiltered() { + return (FilteredList) entriesFiltered.get(); } public boolean isFilterDirectories() { @@ -283,7 +283,7 @@ public void setShowOnlyChainging(boolean showOnlyChainging) { this.showOnlyChainging.set(showOnlyChainging); } - public List getEntriesRenamed() { + public List getEntriesRenamed() { return entriesRenamed; } } diff --git a/src/main/java/drrename/strategy/MediaMetadataRenamingStrategy.java b/src/main/java/drrename/strategy/MediaMetadataRenamingStrategy.java index a247db4f..717358ef 100644 --- a/src/main/java/drrename/strategy/MediaMetadataRenamingStrategy.java +++ b/src/main/java/drrename/strategy/MediaMetadataRenamingStrategy.java @@ -1,5 +1,12 @@ package drrename.strategy; +import com.drew.imaging.ImageMetadataReader; +import com.drew.metadata.Directory; +import com.drew.metadata.Metadata; +import com.drew.metadata.Tag; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; + import java.nio.file.Path; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; @@ -8,14 +15,6 @@ import java.util.List; import java.util.ResourceBundle; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FilenameUtils; - -import com.drew.imaging.ImageMetadataReader; -import com.drew.metadata.Directory; -import com.drew.metadata.Metadata; -import com.drew.metadata.Tag; - @Slf4j public class MediaMetadataRenamingStrategy extends RenamingStrategyProto { diff --git a/src/main/java/drrename/strategy/RegexReplaceRenamingStrategy.java b/src/main/java/drrename/strategy/RegexReplaceRenamingStrategy.java index 53e85413..d6cdad07 100644 --- a/src/main/java/drrename/strategy/RegexReplaceRenamingStrategy.java +++ b/src/main/java/drrename/strategy/RegexReplaceRenamingStrategy.java @@ -1,11 +1,11 @@ package drrename.strategy; +import lombok.extern.slf4j.Slf4j; + import java.nio.file.Path; import java.util.ResourceBundle; import java.util.regex.PatternSyntaxException; -import lombok.extern.slf4j.Slf4j; - @Slf4j public class RegexReplaceRenamingStrategy extends RenamingStrategyProto { diff --git a/src/main/java/drrename/strategy/RenamingStrategy.java b/src/main/java/drrename/strategy/RenamingStrategy.java index d4164a15..d9cf8e33 100644 --- a/src/main/java/drrename/strategy/RenamingStrategy.java +++ b/src/main/java/drrename/strategy/RenamingStrategy.java @@ -35,7 +35,7 @@ public interface RenamingStrategy { Path rename(Path file, BasicFileAttributes attrs) throws IOException, InterruptedException; - void setReplacementStringFrom(String replacement); + RenamingStrategyProto setReplacementStringFrom(String replacement); - void setReplacementStringTo(String replacement); + RenamingStrategyProto setReplacementStringTo(String replacement); } diff --git a/src/main/java/drrename/strategy/RenamingStrategyProto.java b/src/main/java/drrename/strategy/RenamingStrategyProto.java index 376895a9..f69c8c1d 100644 --- a/src/main/java/drrename/strategy/RenamingStrategyProto.java +++ b/src/main/java/drrename/strategy/RenamingStrategyProto.java @@ -1,5 +1,10 @@ package drrename.strategy; +import drrename.RenameUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + import java.io.IOException; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; @@ -9,10 +14,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; - @Slf4j public abstract class RenamingStrategyProto implements RenamingStrategy { @@ -65,7 +66,7 @@ protected Path doRename(final Path file, String nameNew) throws IOException { return file; } log.debug("Renaming" + IOUtils.LINE_SEPARATOR + "old:\t" + nameOld + IOUtils.LINE_SEPARATOR + "new:\t" + nameNew); - return Files.move(file, file.resolveSibling(nameNew)); + return RenameUtil.rename(file, nameNew); } catch (final FileAlreadyExistsException e) { log.debug(e.getLocalizedMessage()); return doRename(file, getFileAlreadyExistsFileName(nameNew, fileNameCounter)); @@ -106,13 +107,15 @@ public Path rename(final Path file, final BasicFileAttributes attrs) throws IOEx } @Override - public void setReplacementStringFrom(final String replacementStringFrom) { + public RenamingStrategyProto setReplacementStringFrom(final String replacementStringFrom) { this.replacementStringFrom = replacementStringFrom; + return this; } @Override - public void setReplacementStringTo(final String replacementStringTo) { + public RenamingStrategyProto setReplacementStringTo(final String replacementStringTo) { this.replacementStringTo = replacementStringTo; + return this; } @Override diff --git a/src/main/java/drrename/ui/FilterableTreeItem.java b/src/main/java/drrename/ui/FilterableTreeItem.java index c89ce071..343ca887 100644 --- a/src/main/java/drrename/ui/FilterableTreeItem.java +++ b/src/main/java/drrename/ui/FilterableTreeItem.java @@ -27,11 +27,10 @@ import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; +import javafx.scene.Node; import javafx.scene.control.TreeItem; import javafx.util.Callback; -import java.util.Collection; -import java.util.LinkedHashSet; import java.util.function.Predicate; public class FilterableTreeItem extends TreeItem { @@ -39,34 +38,49 @@ public class FilterableTreeItem extends TreeItem { // Do not convert this to a local variable. Thinks will break. protected final FilteredList> filteredChildren; - protected final ObjectProperty> predicate = new SimpleObjectProperty<>(); + protected final ObjectProperty> predicate; + + public FilterableTreeItem() { + predicate = new SimpleObjectProperty<>(); + sourceChildren = FXCollections.observableArrayList(this::getExtractorCallback); + filteredChildren = new FilteredList<>(sourceChildren); + init(); + } public FilterableTreeItem(T value) { super(value); + predicate = new SimpleObjectProperty<>(); + sourceChildren = FXCollections.observableArrayList(this::getExtractorCallback); + filteredChildren = new FilteredList<>(sourceChildren); + init(); - sourceChildren = FXCollections.observableArrayList(item -> getExtractorCallback()); + } + + public FilterableTreeItem(T value, Node graphic) { + super(value, graphic); + sourceChildren = FXCollections.observableArrayList(this::getExtractorCallback); filteredChildren = new FilteredList<>(sourceChildren); + predicate = new SimpleObjectProperty<>(); + init(); + } + private void init() { filteredChildren.predicateProperty().bind(Bindings.createObjectBinding(this::buildFilterableListPredicate, predicate)); - filteredChildren.addListener((ListChangeListener>) c -> { while (c.next()) { - Collection> removeFinal = new LinkedHashSet<>(c.getRemoved()); - c.getAddedSubList().forEach(removeFinal::remove); - Collection> addFinal = new LinkedHashSet<>(c.getAddedSubList()); - c.getRemoved().forEach(addFinal::remove); - getChildren().removeAll(removeFinal); - getChildren().addAll(addFinal); + getChildren().removeAll(c.getRemoved()); + getChildren().addAll(c.getAddedSubList()); } }); } /** - * Override to add callbacks to the {@link #sourceChildren} collection. - * See {@link FXCollections#observableArrayList(Callback)} + * Override to add callbacks to the {@link #sourceChildren} collection. See + * {@link FXCollections#observableArrayList(Callback)} + * * @return callbacks that are passed to the observable source list */ - protected Observable[] getExtractorCallback() { + protected Observable[] getExtractorCallback(TreeItem item) { return new Observable[]{}; } diff --git a/src/main/java/drrename/ui/MainController.java b/src/main/java/drrename/ui/MainController.java index cfaf7b34..c768de47 100644 --- a/src/main/java/drrename/ui/MainController.java +++ b/src/main/java/drrename/ui/MainController.java @@ -1,16 +1,16 @@ package drrename.ui; -import drrename.FileTypeByMimeProvider; import drrename.FileTypeProvider; import drrename.RenamingStrategies; -import drrename.strategy.RenamingStrategy; import drrename.config.AppConfig; import drrename.event.MainViewButtonCancelEvent; import drrename.event.MainViewButtonGoEvent; import drrename.filecreator.DummyFileCreatorController; import drrename.kodi.KodiToolsController; -import drrename.model.RenamingEntry; +import drrename.mime.FileTypeByMimeProvider; +import drrename.model.RenamingControl; import drrename.service.EntriesService; +import drrename.strategy.RenamingStrategy; import drrename.ui.mainview.GoCancelButtonsComponentController; import drrename.ui.mainview.ReplacementStringComponentController; import drrename.ui.mainview.StartDirectoryComponentController; @@ -207,12 +207,12 @@ public void initialize(URL url, ResourceBundle resourceBundle) { if (config.isDebug()) applyRandomColors(); - entriesService.getEntriesFiltered().addListener((ListChangeListener) c -> { + entriesService.getEntriesFiltered().addListener((ListChangeListener) c -> { while (c.next()) { executor.execute(() -> { - Collection removeFinal = new LinkedHashSet<>(c.getRemoved()); + Collection removeFinal = new LinkedHashSet<>(c.getRemoved()); c.getAddedSubList().forEach(removeFinal::remove); - Collection addFinal = new LinkedHashSet<>(c.getAddedSubList()); + Collection addFinal = new LinkedHashSet<>(c.getAddedSubList()); c.getRemoved().forEach(addFinal::remove); Platform.runLater(() -> { removeFromContent(removeFinal); @@ -386,32 +386,32 @@ public static String getRandomColorString() { return String.format("#%06x", new Random().nextInt(256 * 256 * 256)); } - private void addToContent(final Collection renamingBeans) { + private void addToContent(final Collection renamingBeans) { renamingBeans.forEach(this::addToContent); } - private void removeFromContent(final Collection renamingBeans) { + private void removeFromContent(final Collection renamingBeans) { if (leftContent.getItems().isEmpty() && rightContent.getItems().isEmpty()) { return; } renamingBeans.forEach(this::removeFromContent); } - private void addToContent(final RenamingEntry renamingEntry) { - leftContent.getItems().add(renamingEntry.getLeftControl()); - rightContent.getItems().add(renamingEntry.getRightControl()); + private void addToContent(final RenamingControl renamingControl) { + leftContent.getItems().add(renamingControl.getLeftControl()); + rightContent.getItems().add(renamingControl.getRightControl()); } - private void removeFromContent(final RenamingEntry renamingEntry) { + private void removeFromContent(final RenamingControl renamingControl) { if (leftContent.getItems().isEmpty() && rightContent.getItems().isEmpty()) { return; } - if (!leftContent.getItems().remove(renamingEntry.getLeftControl())) { - log.warn("Failed to remove {} from left content", renamingEntry.getLeftControl()); + if (!leftContent.getItems().remove(renamingControl.getLeftControl())) { + log.warn("Failed to remove {} from left content", renamingControl.getLeftControl()); } - if (!rightContent.getItems().remove(renamingEntry.getRightControl())) { - log.warn("Failed to remove {} from right content", renamingEntry.getRightControl()); + if (!rightContent.getItems().remove(renamingControl.getRightControl())) { + log.warn("Failed to remove {} from right content", renamingControl.getRightControl()); } } @@ -468,7 +468,7 @@ private void updateFileTypeInfo() { startService(fileTypeService); } - private void initFileTypeService(Collection renamingEntries) { + private void initFileTypeService(Collection renamingEntries) { fileTypeService.cancel(); fileTypeService.reset(); fileTypeService.setRenamingEntries(renamingEntries); diff --git a/src/main/java/drrename/ui/PrimaryStageInitializer.java b/src/main/java/drrename/ui/PrimaryStageInitializer.java index d7f477c7..0bffbdf5 100644 --- a/src/main/java/drrename/ui/PrimaryStageInitializer.java +++ b/src/main/java/drrename/ui/PrimaryStageInitializer.java @@ -1,14 +1,13 @@ package drrename.ui; -import drrename.ui.config.UiConfig; import drrename.event.StageReadyEvent; +import drrename.ui.config.UiConfig; import javafx.application.Platform; import javafx.scene.Scene; import javafx.stage.Stage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.rgielen.fxweaver.core.FxWeaver; -import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; diff --git a/src/main/java/drrename/ui/mainview/controller/FileListComponentController.java b/src/main/java/drrename/ui/mainview/controller/FileListComponentController.java index 26678e1e..0b1350ba 100644 --- a/src/main/java/drrename/ui/mainview/controller/FileListComponentController.java +++ b/src/main/java/drrename/ui/mainview/controller/FileListComponentController.java @@ -6,8 +6,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.rgielen.fxweaver.core.FxmlView; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import java.net.URL; diff --git a/src/main/java/drrename/ui/service/FileTypeService.java b/src/main/java/drrename/ui/service/FileTypeService.java index 8cc23c3c..40163cb5 100644 --- a/src/main/java/drrename/ui/service/FileTypeService.java +++ b/src/main/java/drrename/ui/service/FileTypeService.java @@ -3,7 +3,6 @@ import drrename.FileTypeProvider; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @Service diff --git a/src/main/java/drrename/ui/service/FileTypeTask.java b/src/main/java/drrename/ui/service/FileTypeTask.java index 4c7164e7..1807b84f 100644 --- a/src/main/java/drrename/ui/service/FileTypeTask.java +++ b/src/main/java/drrename/ui/service/FileTypeTask.java @@ -1,13 +1,11 @@ package drrename.ui.service; import drrename.FileTypeProvider; -import drrename.event.StartingFileTypeEvent; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import javafx.application.Platform; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.ApplicationEventPublisher; import java.util.List; @@ -15,12 +13,12 @@ @RequiredArgsConstructor public class FileTypeTask extends Task { - private final List beans; + private final List beans; private final FileTypeProvider fileTypeProvider; - public static void setFileType(FileTypeProvider fileTypeProvider, RenamingEntry renamingEntry) { - final String fileType = fileTypeProvider.getFileType(renamingEntry.getOldPath()); - Platform.runLater(() -> renamingEntry.setFileType(fileType)); + public static void setFileType(FileTypeProvider fileTypeProvider, RenamingControl renamingControl) { + final String fileType = fileTypeProvider.getFileType(renamingControl.getOldPath()); + Platform.runLater(() -> renamingControl.setFileType(fileType)); } @Override @@ -28,7 +26,7 @@ protected Void call() throws Exception { if (beans == null) return null; long cnt = 0; - for (final RenamingEntry p : beans) { + for (final RenamingControl p : beans) { if (Thread.currentThread().isInterrupted()) throw new InterruptedException("Cancelled"); setFileType(fileTypeProvider, p); diff --git a/src/main/java/drrename/ui/service/FilesService.java b/src/main/java/drrename/ui/service/FilesService.java index 41548563..969dd4a1 100644 --- a/src/main/java/drrename/ui/service/FilesService.java +++ b/src/main/java/drrename/ui/service/FilesService.java @@ -1,27 +1,27 @@ package drrename.ui.service; +import drrename.model.RenamingControl; +import javafx.concurrent.Service; + import java.util.ArrayList; import java.util.Collection; import java.util.List; -import drrename.model.RenamingEntry; -import javafx.concurrent.Service; - public abstract class FilesService extends Service { - private List renamingEntries; + private List renamingEntries; public FilesService() { this.renamingEntries = new ArrayList<>(); } - public List getRenamingEntries() { + public List getRenamingEntries() { return renamingEntries; } - public void setRenamingEntries(final Collection renamingEntries) { + public void setRenamingEntries(final Collection renamingEntries) { this.renamingEntries = new ArrayList<>(renamingEntries); } diff --git a/src/main/java/drrename/ui/service/ListDirectoryTask.java b/src/main/java/drrename/ui/service/ListDirectoryTask.java index eee8a7d0..c3402bcb 100644 --- a/src/main/java/drrename/ui/service/ListDirectoryTask.java +++ b/src/main/java/drrename/ui/service/ListDirectoryTask.java @@ -1,7 +1,10 @@ package drrename.ui.service; -import drrename.event.*; -import drrename.model.RenamingEntry; +import drrename.event.ListFilesFinishedEvent; +import drrename.event.NewRenamingEntryEvent; +import drrename.event.StartingListFilesEvent; +import drrename.event.SynchronousUuidEvent; +import drrename.model.RenamingControl; import javafx.concurrent.Task; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; @@ -10,10 +13,12 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; @Slf4j -public class ListDirectoryTask extends Task> { +public class ListDirectoryTask extends Task> { private final Path dir; @@ -27,24 +32,24 @@ public ListDirectoryTask(final Path dir, ApplicationEventPublisher eventPublishe } @Override - protected List call() throws IOException { + protected List call() throws IOException { return getEntries(dir); } - List getEntries(final Path dir) throws IOException { - List result = new ArrayList<>(); + List getEntries(final Path dir) throws IOException { + List result = new ArrayList<>(); SynchronousUuidEvent event = new StartingListFilesEvent(); log.debug("Publishing event {}", event); eventPublisher.publishEvent(event); - List smallList = new ArrayList<>(); + List smallList = new ArrayList<>(); try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path path : stream) { if (Thread.interrupted()) { break; } - RenamingEntry newEntry = new RenamingEntry(path); + RenamingControl newEntry = new RenamingControl(path); result.add(newEntry); smallList.add(newEntry); if(smallList.size() > 3) { diff --git a/src/main/java/drrename/ui/service/ListFilesTask.java b/src/main/java/drrename/ui/service/ListFilesTask.java index 4d4b228d..3dc53d5e 100644 --- a/src/main/java/drrename/ui/service/ListFilesTask.java +++ b/src/main/java/drrename/ui/service/ListFilesTask.java @@ -1,8 +1,8 @@ package drrename.ui.service; -import drrename.event.StartingListFilesEvent; -import drrename.model.RenamingEntry; import drrename.event.NewRenamingEntryEvent; +import drrename.event.StartingListFilesEvent; +import drrename.model.RenamingControl; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -15,7 +15,7 @@ @RequiredArgsConstructor @Slf4j -public class ListFilesTask extends Task> { +public class ListFilesTask extends Task> { private final Collection files; @@ -23,13 +23,13 @@ public class ListFilesTask extends Task> { @Override - protected List call() { + protected List call() { return getEntries(files); } - List getEntries(final Collection files) { - List result = new ArrayList<>(); + List getEntries(final Collection files) { + List result = new ArrayList<>(); var event = new StartingListFilesEvent(); log.debug("Publishing event {}", event); eventPublisher.publishEvent(event); @@ -37,7 +37,7 @@ List getEntries(final Collection files) { if (Thread.interrupted()) { break; } - var newEntry = new RenamingEntry(f); + var newEntry = new RenamingControl(f); result.add(newEntry); eventPublisher.publishEvent(new NewRenamingEntryEvent(event.getUuid(), newEntry)); updateProgress(result.size(), files.size()); diff --git a/src/main/java/drrename/ui/service/LoadPathsService.java b/src/main/java/drrename/ui/service/LoadPathsService.java index 10d78827..24f04d74 100644 --- a/src/main/java/drrename/ui/service/LoadPathsService.java +++ b/src/main/java/drrename/ui/service/LoadPathsService.java @@ -1,6 +1,6 @@ package drrename.ui.service; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import javafx.concurrent.Service; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; @@ -13,14 +13,14 @@ @RequiredArgsConstructor @org.springframework.stereotype.Service -public class LoadPathsService extends Service> { +public class LoadPathsService extends Service> { private Collection files; private final ApplicationEventPublisher eventPublisher; @Override - protected Task> createTask(){ + protected Task> createTask(){ // If 'files' is one entry only, and it's a directory, use ListDirectoryTask, otherwise use ListFilesTask. if(files != null && files.size() == 1 && Files.isDirectory(files.iterator().next())){ return new ListDirectoryTask(files.iterator().next(), eventPublisher); diff --git a/src/main/java/drrename/ui/service/PreviewService.java b/src/main/java/drrename/ui/service/PreviewService.java index 315000e3..f515e08d 100644 --- a/src/main/java/drrename/ui/service/PreviewService.java +++ b/src/main/java/drrename/ui/service/PreviewService.java @@ -1,6 +1,6 @@ package drrename.ui.service; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; import javafx.concurrent.Task; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -9,7 +9,7 @@ import java.util.concurrent.Executor; @Service -public class PreviewService extends StrategyService> { +public class PreviewService extends StrategyService> { private final ApplicationEventPublisher applicationEventPublisher; @@ -19,7 +19,7 @@ public PreviewService(final Executor taskExecutor, ApplicationEventPublisher app } @Override - protected Task> createTask() { + protected Task> createTask() { return new PreviewTask(getRenamingEntries(), getRenamingStrategy(), applicationEventPublisher); } diff --git a/src/main/java/drrename/ui/service/PreviewTask.java b/src/main/java/drrename/ui/service/PreviewTask.java index ddeb5503..c3fbabad 100644 --- a/src/main/java/drrename/ui/service/PreviewTask.java +++ b/src/main/java/drrename/ui/service/PreviewTask.java @@ -1,9 +1,9 @@ package drrename.ui.service; -import drrename.strategy.RenamingStrategy; import drrename.event.FilePreviewEvent; import drrename.event.StartingPreviewEvent; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; +import drrename.strategy.RenamingStrategy; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -14,22 +14,22 @@ @Slf4j @RequiredArgsConstructor -public class PreviewTask extends Task> { +public class PreviewTask extends Task> { - private final List beans; + private final List beans; private final RenamingStrategy renamingStrategy; private final ApplicationEventPublisher applicationEventPublisher; @Override - protected List call() throws Exception { + protected List call() throws Exception { - List result = new ArrayList<>(); + List result = new ArrayList<>(); if (beans == null) return result; var event = new StartingPreviewEvent(); log.debug("Publishing event {}", event); applicationEventPublisher.publishEvent(event); long cnt = 0; - for (final RenamingEntry p : beans) { + for (final RenamingControl p : beans) { if (Thread.currentThread().isInterrupted()) throw new InterruptedException("Cancelled"); String newName = p.preview(renamingStrategy); diff --git a/src/main/java/drrename/ui/service/RenamingService.java b/src/main/java/drrename/ui/service/RenamingService.java index d44cb1d8..f3ca610f 100644 --- a/src/main/java/drrename/ui/service/RenamingService.java +++ b/src/main/java/drrename/ui/service/RenamingService.java @@ -1,8 +1,8 @@ package drrename.ui.service; -import drrename.strategy.RenamingStrategy; import drrename.config.AppConfig; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; +import drrename.strategy.RenamingStrategy; import javafx.concurrent.Service; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; @@ -16,21 +16,21 @@ @RequiredArgsConstructor @Component @Slf4j -public class RenamingService extends Service> { +public class RenamingService extends Service> { private final AppConfig appConfig; private final ApplicationEventPublisher applicationEventPublisher; - private List renamingEntries; + private List renamingEntries; private RenamingStrategy strategy; - public List getRenamingEntries() { + public List getRenamingEntries() { return renamingEntries; } - public void setRenamingEntries(final List renamingEntries) { + public void setRenamingEntries(final List renamingEntries) { this.renamingEntries = renamingEntries; } @@ -46,7 +46,7 @@ public void setStrategy(final RenamingStrategy strategy) { } @Override - protected Task> createTask() { + protected Task> createTask() { return new RenamingTask(renamingEntries, strategy, appConfig, applicationEventPublisher); } diff --git a/src/main/java/drrename/ui/service/RenamingTask.java b/src/main/java/drrename/ui/service/RenamingTask.java index ac3eebd4..4b51c6c3 100644 --- a/src/main/java/drrename/ui/service/RenamingTask.java +++ b/src/main/java/drrename/ui/service/RenamingTask.java @@ -1,10 +1,10 @@ package drrename.ui.service; -import drrename.strategy.RenamingStrategy; import drrename.config.AppConfig; import drrename.event.FileRenamedEvent; import drrename.event.StartingRenameEvent; -import drrename.model.RenamingEntry; +import drrename.model.RenamingControl; +import drrename.strategy.RenamingStrategy; import javafx.concurrent.Task; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; @@ -14,24 +14,24 @@ import java.util.List; @RequiredArgsConstructor -public class RenamingTask extends Task> { +public class RenamingTask extends Task> { - private final List elements; + private final List elements; private final RenamingStrategy strategy; private final AppConfig config; private final ApplicationEventPublisher applicationEventPublisher; @Override - protected List call() throws InterruptedException { + protected List call() throws InterruptedException { - List result = new ArrayList<>(); + List result = new ArrayList<>(); var event = new StartingRenameEvent(); applicationEventPublisher.publishEvent(event); long cnt = 0; - for (final RenamingEntry b : elements) { + for (final RenamingControl b : elements) { if (Thread.currentThread().isInterrupted()) throw new InterruptedException("Cancelled"); - if (b.willChange()) { + if (b.isWillChange()) { Path p = b.rename(strategy); if(!b.getOldPath().equals(p)){ result.add(b); diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index d53038c9..53f21cd6 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -22,4 +22,7 @@ requires org.apache.commons.text; requires metadata.extractor; requires jodd.util; + requires spring.cloud.openfeign.core; + requires spring.web; + requires jasypt.spring.boot; } \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 7121bf29..8718a446 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,16 +1,23 @@ spring: main: - web: - application-type: none banner-mode: off logging: level: root: info drrename: debug + com: + ulisesbocchio: warn pattern: console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta([%thread]) %yellow(%logger{20}.%M\\(%class{0}.java:%line\\)) - %msg%throwable%n" +feign: + client: + config: + default: + connectTimeout: 5000 + readTimeout: 5000 + loggerLevel: none app: ui: @@ -22,4 +29,11 @@ app: loop-delay-ms: 500 reset-delay-ms: 1000 debug: false + kodi: + themoviedb: + api-key: "ENC(CmZ0CbclHAqHtwYOj+CQWtnHbHji2D69NKDiXllj948WUfrc12oOq48yRL82jItl4AtJYpYtRDq4y2fi0kYhDf24hXfs1Z8Tva0lp4xP/0E=)" + base-url: https://api.themoviedb.org/3 + include-adult: true + images: + base-url: https://image.tmdb.org/t/p diff --git a/src/main/resources/css/root.css b/src/main/resources/css/root.css index 836ecd3e..52d1753c 100644 --- a/src/main/resources/css/root.css +++ b/src/main/resources/css/root.css @@ -1,5 +1,8 @@ .root{ -fx-font-family: "Arial"; } +.tree-cell { + -fx-wrap-text: true; +} diff --git a/src/main/resources/fxml/DummyFileCreator.fxml b/src/main/resources/fxml/DummyFileCreator.fxml index 8a93a30d..dea1655b 100644 --- a/src/main/resources/fxml/DummyFileCreator.fxml +++ b/src/main/resources/fxml/DummyFileCreator.fxml @@ -1,12 +1,8 @@ - - - + - - diff --git a/src/main/resources/fxml/FileListComponent.fxml b/src/main/resources/fxml/FileListComponent.fxml index ad69d544..b6becea8 100644 --- a/src/main/resources/fxml/FileListComponent.fxml +++ b/src/main/resources/fxml/FileListComponent.fxml @@ -1,10 +1,10 @@ + - diff --git a/src/main/resources/fxml/GoCancelButtonsComponent.fxml b/src/main/resources/fxml/GoCancelButtonsComponent.fxml index c6777aae..ceb4989f 100644 --- a/src/main/resources/fxml/GoCancelButtonsComponent.fxml +++ b/src/main/resources/fxml/GoCancelButtonsComponent.fxml @@ -1,9 +1,8 @@ + - - diff --git a/src/main/resources/fxml/KodiTools.fxml b/src/main/resources/fxml/KodiTools.fxml index 3d4f93ca..43ec0c77 100644 --- a/src/main/resources/fxml/KodiTools.fxml +++ b/src/main/resources/fxml/KodiTools.fxml @@ -42,8 +42,10 @@ - - + + + + diff --git a/src/test/java/com/github/drrename/AbstractRenamingStrategyTest.java b/src/test/java/com/github/drrename/AbstractRenamingStrategyTest.java index 27342129..ae00f04b 100644 --- a/src/test/java/com/github/drrename/AbstractRenamingStrategyTest.java +++ b/src/test/java/com/github/drrename/AbstractRenamingStrategyTest.java @@ -1,16 +1,14 @@ package com.github.drrename; -import java.io.File; -import java.nio.file.Path; - import com.github.ktools1000.io.BackupCreator; -import org.apache.commons.io.FileUtils; - - import drrename.strategy.RenamingStrategy; +import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import java.io.File; +import java.nio.file.Path; + public abstract class AbstractRenamingStrategyTest { @BeforeEach diff --git a/src/test/java/com/github/drrename/strategy/MediaMetadataRenamingStrategyTest.java b/src/test/java/com/github/drrename/strategy/MediaMetadataRenamingStrategyTest.java index d063c1a5..121adbcc 100644 --- a/src/test/java/com/github/drrename/strategy/MediaMetadataRenamingStrategyTest.java +++ b/src/test/java/com/github/drrename/strategy/MediaMetadataRenamingStrategyTest.java @@ -1,17 +1,16 @@ package com.github.drrename.strategy; -import java.io.File; -import java.util.Locale; -import java.util.ResourceBundle; - - import com.github.drrename.AbstractRenamingStrategyTest; -import drrename.strategy.RenamingStrategy; import drrename.strategy.MediaMetadataRenamingStrategy; +import drrename.strategy.RenamingStrategy; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.io.File; +import java.util.Locale; +import java.util.ResourceBundle; + public class MediaMetadataRenamingStrategyTest extends AbstractRenamingStrategyTest { @BeforeAll diff --git a/src/test/java/com/github/drrename/strategy/ToLowerCaseRenamingStrategyTest.java b/src/test/java/com/github/drrename/strategy/ToLowerCaseRenamingStrategyTest.java index 8e4d9d08..87c4e37d 100644 --- a/src/test/java/com/github/drrename/strategy/ToLowerCaseRenamingStrategyTest.java +++ b/src/test/java/com/github/drrename/strategy/ToLowerCaseRenamingStrategyTest.java @@ -1,9 +1,9 @@ package com.github.drrename.strategy; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - +import com.github.drrename.AbstractRenamingStrategyTest; +import drrename.strategy.RenamingStrategy; +import drrename.strategy.ToLowerCaseRenamingStrategy; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -12,10 +12,9 @@ import java.util.Locale; import java.util.ResourceBundle; -import com.github.drrename.AbstractRenamingStrategyTest; -import drrename.strategy.RenamingStrategy; -import drrename.strategy.ToLowerCaseRenamingStrategy; -import org.junit.jupiter.api.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ToLowerCaseRenamingStrategyTest extends AbstractRenamingStrategyTest { diff --git a/src/test/java/drrename/RenameUtilTest.java b/src/test/java/drrename/RenameUtilTest.java index 938aefac..c55f88fa 100644 --- a/src/test/java/drrename/RenameUtilTest.java +++ b/src/test/java/drrename/RenameUtilTest.java @@ -1,16 +1,62 @@ package drrename; +import com.github.ktools1000.io.BackupCreator; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.*; class RenameUtilTest { + Path fileToRename = Paths.get("src/test/resources/rename-tests/some-dir/some-file.txt"); + + File backupFile; + + Path newFile; + @BeforeEach - void setUp() { + void setUp() throws FileNotFoundException { + backupFile = new BackupCreator().makeBackup(fileToRename.toFile()); } @AfterEach - void tearDown() { + void tearDown() throws IOException { + new BackupCreator().restoreBackup(backupFile); + backupFile.delete(); + Files.delete(newFile); + } + + @Test + void rename() throws IOException { + + var newName = "some2-file2.txt"; + RenameUtil.rename(fileToRename, newName); + newFile = Paths.get("src/test/resources/rename-tests/some-dir", newName); + assertTrue(Files.exists(newFile)); + assertTrue(Files.isReadable(newFile)); + } + + + @Test + void renameConflict() throws IOException { + + var newName = "some2-file2.txt"; + newFile = Paths.get("src/test/resources/rename-tests/some-dir", newName); + Files.createFile(newFile); + + Throwable throwable = assertThrows(FileAlreadyExistsException.class, () -> { + RenameUtil.rename(fileToRename, newName); + }); + assertEquals(FileAlreadyExistsException.class, throwable.getClass()); } diff --git a/src/test/java/drrename/kodi/KodiUtilTest.java b/src/test/java/drrename/kodi/KodiUtilTest.java new file mode 100644 index 00000000..aa8c29a8 --- /dev/null +++ b/src/test/java/drrename/kodi/KodiUtilTest.java @@ -0,0 +1,64 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class KodiUtilTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void testHappyCaseName(){ + var directoryString = "Frozen (2011)"; + var expectedString = "Frozen"; + assertEquals(expectedString, KodiUtil.getMovieNameFromDirectoryName(directoryString)); + } + + @Test + void testHappyCaseYear(){ + var directoryString = "Frozen (2011)"; + var expectedNumber = 2011; + assertEquals(expectedNumber, KodiUtil.getMovieYearFromDirectoryName(directoryString)); + } + + @Test + void testMissingYear(){ + var directoryString = "Frozen"; + var expectedString = "Frozen"; + assertEquals(expectedString, KodiUtil.getMovieNameFromDirectoryName(directoryString)); + } + + @Test + void testMissingYear2(){ + var directoryString = "Frozen"; + assertNull(KodiUtil.getMovieYearFromDirectoryName(directoryString)); + } +} \ No newline at end of file diff --git a/src/test/java/drrename/model/nfo/NfoFileParserTest.java b/src/test/java/drrename/kodi/treeitem/nfo/NfoContentCoverCheckerTest.java similarity index 70% rename from src/test/java/drrename/model/nfo/NfoFileParserTest.java rename to src/test/java/drrename/kodi/treeitem/nfo/NfoContentCoverCheckerTest.java index 781780d1..47f724cb 100644 --- a/src/test/java/drrename/model/nfo/NfoFileParserTest.java +++ b/src/test/java/drrename/kodi/treeitem/nfo/NfoContentCoverCheckerTest.java @@ -17,32 +17,31 @@ * along with this program. If not, see . */ -package drrename.model.nfo; +package drrename.kodi.treeitem.nfo; +import drrename.kodi.nfo.NfoContentCoverChecker; +import drrename.kodi.nfo.NfoFileContentType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; import java.nio.file.Paths; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; -class NfoFileParserTest { +class NfoContentCoverCheckerTest { @BeforeEach void setUp() { - } @AfterEach void tearDown() { - } @Test - void parse() throws IOException { - var result = new NfoFileParser().parse(Paths.get("src/test/resources/test-nfo-01.nfo")); - System.out.println(result); + void test01(){ + var result = new NfoContentCoverChecker().checkNfoFile(Paths.get("src/test/resources/kodi/Cover Test Movie (1999)/movie.nfo")); + assertEquals(NfoFileContentType.MISSING_POSTER, result); } } \ No newline at end of file diff --git a/src/test/java/drrename/kodi/treeitem/nfo/NfoContentYearCheckerTest.java b/src/test/java/drrename/kodi/treeitem/nfo/NfoContentYearCheckerTest.java new file mode 100644 index 00000000..cbc34c76 --- /dev/null +++ b/src/test/java/drrename/kodi/treeitem/nfo/NfoContentYearCheckerTest.java @@ -0,0 +1,65 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.treeitem.nfo; + +import drrename.kodi.nfo.NfoContentYearChecker; +import drrename.kodi.nfo.NfoFileContentType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NfoContentYearCheckerTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void checkValidFile() { + var result = new NfoContentYearChecker().checkNfoFile(Paths.get("src/test/resources/kodi/Some Movie (2000)/movie.nfo")); + assertEquals(NfoFileContentType.VALID_YEAR, result); + } + + @Test + void checkInValidFile() { + var result = new NfoContentYearChecker().checkNfoFile(Paths.get("src/test/resources/kodi/Some Movie (2000)/wrong-format.nfo")); + assertEquals(NfoFileContentType.INVALID_FILE, result); + } + + @Test + void checkUrlOnlyFile() { + var result = new NfoContentYearChecker().checkNfoFile(Paths.get("src/test/resources/kodi/UrlOnlyMovie/movie.nfo")); + assertEquals(NfoFileContentType.URL_ONLY_FILE, result); + } + + @Test + void checkYearlessFile() { + var result = new NfoContentYearChecker().checkNfoFile(Paths.get("src/test/resources/kodi/Yearless Movie/movie.nfo")); + assertEquals(NfoFileContentType.MISSING_YEAR, result); + } +} \ No newline at end of file diff --git a/src/test/java/drrename/kodi/treeitem/nfo/NfoFileNameCheckerTest.java b/src/test/java/drrename/kodi/treeitem/nfo/NfoFileNameCheckerTest.java new file mode 100644 index 00000000..dd75bca1 --- /dev/null +++ b/src/test/java/drrename/kodi/treeitem/nfo/NfoFileNameCheckerTest.java @@ -0,0 +1,59 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.treeitem.nfo; + +import drrename.kodi.nfo.NfoFileNameChecker; +import drrename.kodi.nfo.NfoFileNameType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NfoFileNameCheckerTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void checkNoFile() { + var result = new NfoFileNameChecker().checkDir(Paths.get("src/test/resources/kodi/Maleficent 2 (2019)")); + assertEquals(NfoFileNameType.NO_FILE, result); + } + + @Test + void checkMovieName() { + var result = new NfoFileNameChecker().checkDir(Paths.get("src/test/resources/kodi/test01")); + assertEquals(NfoFileNameType.MOVIE_NAME, result); + } + + @Test + void checkDefaultName() { + var result = new NfoFileNameChecker().checkDir(Paths.get("src/test/resources/kodi/test02")); + assertEquals(NfoFileNameType.DEFAULT_NAME, result); + } +} \ No newline at end of file diff --git a/src/test/java/drrename/kodi/treeitem/nfo/NfoFileParserTest.java b/src/test/java/drrename/kodi/treeitem/nfo/NfoFileParserTest.java new file mode 100644 index 00000000..1b02bfe5 --- /dev/null +++ b/src/test/java/drrename/kodi/treeitem/nfo/NfoFileParserTest.java @@ -0,0 +1,67 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.kodi.treeitem.nfo; + +import drrename.kodi.nfo.NfoFileParser; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class NfoFileParserTest { + + @BeforeEach + void setUp() { + + } + + @AfterEach + void tearDown() { + + } + + @Test + void parse01() throws IOException { + var result = new NfoFileParser().parse(Paths.get("src/test/resources/kodi/test-nfo-01.nfo")); + assertNotNull(result.getMovie().getTitle()); + assertNotNull(result.getUrl()); + } + @Test + void parse02() throws IOException { + var result = new NfoFileParser().parse(Paths.get("src/test/resources/kodi/test-nfo-02.nfo")); + assertNotNull(result.getUrl()); + assertNotNull(result.getMovie()); + } + @Test + void parse03() throws IOException { + var result = new NfoFileParser().parse(Paths.get("src/test/resources/kodi/url-only.nfo")); + assertNotNull(result.getUrl()); + } + + @Test + void emptyLine() throws IOException { + var result = new NfoFileParser().parse(Paths.get("src/test/resources/kodi/empty-line.nfo")); + System.out.println(result); + } +} \ No newline at end of file diff --git a/src/test/java/drrename/mime/FileTypeByMimeProviderTest.java b/src/test/java/drrename/mime/FileTypeByMimeProviderTest.java new file mode 100644 index 00000000..25db6a4c --- /dev/null +++ b/src/test/java/drrename/mime/FileTypeByMimeProviderTest.java @@ -0,0 +1,58 @@ +/* + * Dr.Rename - A Minimalistic Batch Renamer + * + * Copyright (C) 2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package drrename.mime; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FileTypeByMimeProviderTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void getFileTypeNfo() { + var result = new FileTypeByMimeProvider().getFileType(Paths.get("src/test/resources/kodi/test-nfo-01.nfo")); + assertTrue(result.startsWith("text")); + } + + @Test + void getFileTypeDirectory() { + var result = new FileTypeByMimeProvider().getFileType(Paths.get("src/test/resources/kodi/Maleficent 2 (2019)")); + assertEquals("directory", result); + } + + @Test + void getFileTypeImage() { + var result = new FileTypeByMimeProvider().getFileType(Paths.get("src/test/resources/kodi/kodi-logo.png")); + assertTrue(result.startsWith("image")); + } +} \ No newline at end of file diff --git a/src/test/resources/kodi/Cover Test Movie (1999)/movie.nfo b/src/test/resources/kodi/Cover Test Movie (1999)/movie.nfo new file mode 100644 index 00000000..302bc5ab --- /dev/null +++ b/src/test/resources/kodi/Cover Test Movie (1999)/movie.nfo @@ -0,0 +1,8 @@ + +The Russians Are Cumming +2020 +Adult + + + folder.jpg + \ No newline at end of file diff --git a/src/test/resources/kodi/Maleficent 2 (2019)/movie.mkv b/src/test/resources/kodi/Maleficent 2 (2019)/movie.mkv new file mode 100644 index 00000000..3c546eb2 --- /dev/null +++ b/src/test/resources/kodi/Maleficent 2 (2019)/movie.mkv @@ -0,0 +1 @@ +dummy file \ No newline at end of file diff --git a/src/test/resources/kodi/Some Movie (2000)/movie.nfo b/src/test/resources/kodi/Some Movie (2000)/movie.nfo new file mode 100755 index 00000000..154c60dd --- /dev/null +++ b/src/test/resources/kodi/Some Movie (2000)/movie.nfo @@ -0,0 +1,5 @@ + +Martial arts +2000 + +https://www.imdb.com/title/tt2888046/ diff --git a/src/test/resources/kodi/Some Movie (2000)/wrong-format.nfo b/src/test/resources/kodi/Some Movie (2000)/wrong-format.nfo new file mode 100644 index 00000000..8be36608 --- /dev/null +++ b/src/test/resources/kodi/Some Movie (2000)/wrong-format.nfo @@ -0,0 +1,17 @@ +I Feel Pretty (2018) + +Release Date ... : 11.09.2018 +Kinostart (D) .. : 10.05.2018 + +Runtime ........ : 110:02 +IMDB-Rating .... : 5,3/10 + +Ratecontrol .... : crf 20 +Video .......... : 1920x808 @ 2877 kbps +Audio 1 ........ : German DTS 5.1 @ 1509 kbps +Audio 2 ........ : English DTS 5.1 @ 1509 kbps + +Forced Subs .....: German +Vobsubs ........ : German, German Forced + +https://www.imdb.com/title/tt6791096/ \ No newline at end of file diff --git a/src/test/resources/kodi/UrlOnlyMovie/movie.nfo b/src/test/resources/kodi/UrlOnlyMovie/movie.nfo new file mode 100755 index 00000000..85427045 --- /dev/null +++ b/src/test/resources/kodi/UrlOnlyMovie/movie.nfo @@ -0,0 +1 @@ +http://www.imdb.com/title/tt2952602/ \ No newline at end of file diff --git a/src/test/resources/kodi/Yearless Movie/movie.nfo b/src/test/resources/kodi/Yearless Movie/movie.nfo new file mode 100755 index 00000000..9f16e265 --- /dev/null +++ b/src/test/resources/kodi/Yearless Movie/movie.nfo @@ -0,0 +1,4 @@ + +Martial arts + +https://www.imdb.com/title/tt2888046/ diff --git a/src/test/resources/kodi/empty-line.nfo b/src/test/resources/kodi/empty-line.nfo new file mode 100644 index 00000000..7263dc69 --- /dev/null +++ b/src/test/resources/kodi/empty-line.nfo @@ -0,0 +1,9 @@ + +title +2018 +genre + + folder.jpg + + +https://www.imdb.com/title/111/ diff --git a/src/test/resources/kodi/kodi-logo.png b/src/test/resources/kodi/kodi-logo.png new file mode 100644 index 00000000..d8afe745 Binary files /dev/null and b/src/test/resources/kodi/kodi-logo.png differ diff --git a/src/test/resources/test-nfo-01.nfo b/src/test/resources/kodi/test-nfo-01.nfo similarity index 96% rename from src/test/resources/test-nfo-01.nfo rename to src/test/resources/kodi/test-nfo-01.nfo index 9501e3f2..aaeedccd 100755 --- a/src/test/resources/test-nfo-01.nfo +++ b/src/test/resources/kodi/test-nfo-01.nfo @@ -1,5 +1,5 @@ - - Kung Fu Killer - Martial arts - + + Kung Fu Killer + Martial arts + http://www.imdb.com/title/tt2952602/ \ No newline at end of file diff --git a/src/test/resources/kodi/test-nfo-02.nfo b/src/test/resources/kodi/test-nfo-02.nfo new file mode 100644 index 00000000..1646284d --- /dev/null +++ b/src/test/resources/kodi/test-nfo-02.nfo @@ -0,0 +1,4 @@ + +X-Mas + +https://www.imdb.com/title/tt1083448/ diff --git a/src/test/resources/kodi/test01/test01.nfo b/src/test/resources/kodi/test01/test01.nfo new file mode 100644 index 00000000..e69de29b diff --git a/src/test/resources/kodi/test02/movie.nfo b/src/test/resources/kodi/test02/movie.nfo new file mode 100644 index 00000000..e69de29b diff --git a/src/test/resources/kodi/url-only.nfo b/src/test/resources/kodi/url-only.nfo new file mode 100755 index 00000000..85427045 --- /dev/null +++ b/src/test/resources/kodi/url-only.nfo @@ -0,0 +1 @@ +http://www.imdb.com/title/tt2952602/ \ No newline at end of file diff --git a/src/test/resources/rename-tests/some-dir/some-file.txt b/src/test/resources/rename-tests/some-dir/some-file.txt new file mode 100644 index 00000000..e69de29b