diff --git a/.gitignore b/.gitignore index 32bcbc8..1783511 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /.idea/ /target/ .DS_Store -/MangranaCommons.iml -/tokens/ -/src/main/resources/credentials.json +/MangranaCommons.iml \ No newline at end of file diff --git a/pom.xml b/pom.xml index d7039b6..adaee2e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ tv.mangrana mangrana-commons - 4.1.3 + 6.0.0 8 @@ -43,25 +43,6 @@ 4.4 - - - com.google.apis - google-api-services-drive - v3-rev20220508-1.32.1 - - - - com.google.api-client - google-api-client - 1.35.1 - - - - com.google.oauth-client - google-oauth-client-jetty - 1.34.1 - - org.testng diff --git a/src/main/java/org/o7planning/googledrive/example/GoogleDriveUtils.java b/src/main/java/org/o7planning/googledrive/example/GoogleDriveUtils.java deleted file mode 100644 index a7a5567..0000000 --- a/src/main/java/org/o7planning/googledrive/example/GoogleDriveUtils.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.o7planning.googledrive.example; - - -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; -import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; -import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; -import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.gson.GsonFactory; -import com.google.api.client.util.store.FileDataStoreFactory; -import com.google.api.services.drive.Drive; -import com.google.api.services.drive.DriveScopes; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.List; - -import static tv.mangrana.utils.Output.log; - -public class GoogleDriveUtils { - - private static final String APPLICATION_NAME = "Google Drive API Java Quickstart"; - - private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance(); - - private static final List SCOPES = Collections.singletonList(DriveScopes.DRIVE); - - private static final String CREDENTIALS_FILE_PATH = "/credentials.json"; - - private static final String TOKENS_DIRECTORY_PATH = "tokens"; - - // Global instance of the HTTP transport. - private static HttpTransport HTTP_TRANSPORT; - - private static Drive _driveService; - - static { - try { - HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport(); - } catch (Throwable t) { - t.printStackTrace(); - System.exit(1); - } - } - - public static Credential getCredentials() throws IOException { - - // Load client secrets. - InputStream in = GoogleDriveUtils.class.getResourceAsStream(CREDENTIALS_FILE_PATH); - if (in == null) { - throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH); - } - GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in)); - - // Build flow and trigger user authorization request. - GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( - HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES) - .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH))) - .setAccessType("offline") - .build(); - LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build(); - Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); - //returns an authorized Credential object. - return credential; - } - - public static Drive getDriveService() throws IOException { - if (_driveService != null) { - return _driveService; - } - Credential credential = getCredentials(); - // - _driveService = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) // - .setApplicationName(APPLICATION_NAME).build(); - log("Google Drive service initialized"); - return _driveService; - } - -} \ No newline at end of file diff --git a/src/main/java/tv/mangrana/google/api/client/QuickTester.java b/src/main/java/tv/mangrana/google/api/client/QuickTester.java deleted file mode 100644 index 5c2576a..0000000 --- a/src/main/java/tv/mangrana/google/api/client/QuickTester.java +++ /dev/null @@ -1,36 +0,0 @@ -package tv.mangrana.google.api.client; - -import tv.mangrana.exception.NoElementFoundException; -import com.google.api.services.drive.Drive; -import com.google.api.services.drive.model.TeamDrive; -import org.o7planning.googledrive.example.GoogleDriveUtils; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; - -import static tv.mangrana.utils.Output.log; - -public class QuickTester { - - public static void main(String[] args) throws IOException, NoElementFoundException { - new QuickTester() - .listTDs(); - } - - public QuickTester() throws IOException { - service = GoogleDriveUtils.getDriveService(); - } - - Drive service; - - private void listTDs() throws IOException, NoElementFoundException { - List list = Optional.ofNullable( - service.teamdrives().list().execute().getTeamDrives()) - .orElseThrow(() -> new NoElementFoundException("No TDs found :(")); - - list.forEach(td -> log(td.getName())); - log("Ok, if you have been seeing some TDs in the output, that means GoogleDriveUtils works \uD83D\uDC4D"); - } - -} diff --git a/src/main/java/tv/mangrana/google/api/client/gateway/GoogleDriveApiGateway.java b/src/main/java/tv/mangrana/google/api/client/gateway/GoogleDriveApiGateway.java deleted file mode 100644 index 91f2ca1..0000000 --- a/src/main/java/tv/mangrana/google/api/client/gateway/GoogleDriveApiGateway.java +++ /dev/null @@ -1,162 +0,0 @@ -package tv.mangrana.google.api.client.gateway; - -import tv.mangrana.exception.NoElementFoundException; -import com.google.api.services.drive.Drive; -import com.google.api.services.drive.model.File; -import com.google.api.services.drive.model.FileList; -import org.apache.commons.collections4.CollectionUtils; -import org.o7planning.googledrive.example.GoogleDriveUtils; - -import java.io.IOException; -import java.util.*; - -import static tv.mangrana.utils.Output.log; - -public class GoogleDriveApiGateway { - - Drive service; - - public enum GoogleElementType {FOLDER, VIDEO} - - public GoogleDriveApiGateway() throws IOException { - service = GoogleDriveUtils.getDriveService(); - } - - public File lookupElementById(String elementId) throws IOException { - return service.files() - .get(elementId) - .setSupportsTeamDrives(true) - .execute(); - } - - public File lookupElementByName(String elementName, GoogleElementType type, String relatedTeamDriveId) throws IOException, NoElementFoundException { - String query = "name = '" + elementName.replace("'","\\'") + "'" - + " and trashed=false" - + getTypeFilterQuery(type); - - FileList fileList = - service.files() - .list() - .setCorpora("drive") - .setTeamDriveId(relatedTeamDriveId) - .setIncludeItemsFromAllDrives(true) - .setSupportsTeamDrives(true) - .setQ(query) - .execute(); - - List files = Optional.ofNullable( - fileList.getFiles()) - .orElseThrow(() -> new NoElementFoundException("element not found by name: " + elementName)); - - if (CollectionUtils.isNotEmpty(files)) { - if (files.size() > 1) { - log("WARN: There are more than one matching element!!!"); - files.forEach(fl -> log("> element with name {0} an id {1}", fl.getName(), fl.getId())); - } - return files.get(0); - } else { - throw new NoElementFoundException("no elements in the list xO"); - } - } - - public List getChildrenFromParent(File parent, boolean onlyFolders) { - String query = - "trashed=false and "+ - (onlyFolders ? "mimeType = 'application/vnd.google-apps.folder' and " : "")+ - "'"+parent.getId()+"' in parents"; - - return getChildrenCommonCall(query); - } - - public File getChildFromParentByName(String name, File parent, boolean onlyFolder) throws NoElementFoundException { - String query = "name = '" + name.replace("'","\\'") + "'" + - " and trashed=false and "+ - (onlyFolder ? "mimeType = 'application/vnd.google-apps.folder' and " : "")+ - "'"+parent.getId()+"' in parents"; - List children = getChildrenCommonCall(query); - if (children.isEmpty()) throw new NoElementFoundException("no elements in the list xO"); - if (children.size() > 1) log("WARNING: more than one element here not expected for <{0}> and parent <{1}>", name, parent.getName()); - return children.get(0); - } - - private List getChildrenCommonCall(String query) { - List fullFileList = new ArrayList<>(); - String pageToken = null; - do { - try { - FileList fileList = service.files() - .list() - .setQ(query) - .setIncludeItemsFromAllDrives(true) - .setSupportsTeamDrives(true) - .setFields("nextPageToken, files(id, name)") - .setPageToken(pageToken) - .setOrderBy("name") - .execute(); - - fullFileList.addAll(fileList.getFiles()); - pageToken = fileList.getNextPageToken(); - } catch (IOException e) { - log("ERROR during api call"); - e.printStackTrace(); - } - } while (pageToken != null); - - return fullFileList; - } - - public void copyFile(String fileId, String destinationFolderId) throws IOException { - File newFileReference = new File(); - newFileReference.setParents(Collections.singletonList(destinationFolderId)); - service.files() - .copy(fileId, newFileReference) - .setSupportsTeamDrives(true) - .execute(); - } - - public void moveFile(File file, String destinationFolderId, String newFileName) throws IOException { - String parentId = getParent(file.getId()); - File newFileReference = new File(); - newFileReference.setName(newFileName); - service.files() - .update(file.getId(), newFileReference) - .setSupportsTeamDrives(true) - .setAddParents(destinationFolderId) - .setRemoveParents(parentId) - .setFields("id, name, parents") - .execute(); - } - - private String getParent(String fileId) throws IOException { - File file = service.files() - .get(fileId) - .setFields("parents") - .setSupportsTeamDrives(true) - .execute(); - return file.getParents().get(0); - } - - public File createFolder(String name, String parentFolderId) throws IOException { - File fileMetadata = new File(); - fileMetadata.setName(name); - fileMetadata.setMimeType("application/vnd.google-apps.folder"); - fileMetadata.setParents(Collections.singletonList(parentFolderId)); - return service - .files() - .create(fileMetadata) - .setSupportsTeamDrives(true) - .execute(); - } - - private String getTypeFilterQuery(GoogleElementType type) { - switch (type) { - case VIDEO: - return " and mimeType contains 'video'"; - case FOLDER: - return " and mimeType = 'application/vnd.google-apps.folder'"; - default: - return ""; - } - } - -} diff --git a/src/main/java/tv/mangrana/jobs/JobsFileStorage.java b/src/main/java/tv/mangrana/jobs/JobsFileStorage.java index e0d3d50..579b4c2 100644 --- a/src/main/java/tv/mangrana/jobs/JobsFileStorage.java +++ b/src/main/java/tv/mangrana/jobs/JobsFileStorage.java @@ -1,6 +1,7 @@ package tv.mangrana.jobs; import org.apache.commons.lang.StringUtils; +import tv.mangrana.exception.IncorrectWorkingReferencesException; import java.io.FileWriter; import java.io.IOException; @@ -10,7 +11,9 @@ import java.nio.file.Paths; import java.text.MessageFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -26,8 +29,11 @@ public class JobsFileStorage { static final String ELEMENT_NAME = "element"; public final String JOB_LINE_FORMAT; + private static final String RESUME_FILE = JobFileManager.getResumeFile(); - public JobsFileStorage() { + private final List> linesInfo; + + public JobsFileStorage() throws IncorrectWorkingReferencesException { String preFormat = "{COMPLETED_DATE}: {5} | {JOB_TYPE}: {0} | {HASH}: {1} | {ARR_ID}: {2} | {INTERNET_DB_ID}: {3} | {ELEMENT_NAME}: {4}"; JOB_LINE_FORMAT = preFormat .replace("{COMPLETED_DATE}", COMPLETED_DATE) @@ -36,8 +42,36 @@ public class JobsFileStorage { .replace("{ARR_ID}", ARR_ID) .replace("{INTERNET_DB_ID}", INTERNET_DB_ID) .replace("{ELEMENT_NAME}", ELEMENT_NAME); + + linesInfo = getInfoFromFile(); + } + + private List> getInfoFromFile() throws IncorrectWorkingReferencesException { + List> newLinesInfo = new ArrayList<>(); + try (Stream linesStream = Files.lines(Paths.get(RESUME_FILE))) { + linesStream + .filter(probableLine -> StringUtils.isNotEmpty(probableLine) && probableLine.contains("|")) + .forEach(line -> newLinesInfo.add(line2Map(line))); + } catch (IOException e) { + e.printStackTrace(); + throw new IncorrectWorkingReferencesException("A problem occurred when trying to get jobs file info"); + } + return newLinesInfo; + } + + private Map line2Map(String line) { + Map mappedLine = new HashMap<>(); + String[] infoList = line.split("\\|"); + for (String elementInfo : infoList) { + if (!elementInfo.trim().startsWith(COMPLETED_DATE)) { + String[] fieldValue = elementInfo.split(":"); + String field = fieldValue[0].trim(); + String value = fieldValue[1].trim(); + mappedLine.put(field, value); + } + } + return mappedLine; } - String resumeFile = JobFileManager.getResumeFile(); public void persistCompleted(String type, String downloadId, int arrId, int iId, String element, LocalDateTime time){ String jobLine = MessageFormat.format(JOB_LINE_FORMAT, @@ -55,7 +89,7 @@ public class JobsFileStorage { } void addLine(String jobLine) { - try (FileWriter fw = new FileWriter(resumeFile, true); + try (FileWriter fw = new FileWriter(RESUME_FILE, true); PrintWriter pw = new PrintWriter(fw)) { pw.println(jobLine); @@ -65,31 +99,11 @@ public class JobsFileStorage { } public String getIIDByElement(String element) { - try (Stream linesStream = Files.lines(Paths.get(resumeFile))) { - return linesStream - .map(this::line2Map) - .filter(mappedLine -> mappedLine.get(ELEMENT_NAME).equals(element)) - .findAny() - .map(found -> found.get(INTERNET_DB_ID)) - .orElse(null); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - private Map line2Map(String line) { - Map mappedLine = new HashMap<>(); - String[] infoList = line.split("\\|"); - for (String elementInfo : infoList) { - if (!elementInfo.trim().startsWith(COMPLETED_DATE)) { - String[] fieldValue = elementInfo.split(":"); - String field = fieldValue[0].trim(); - String value = fieldValue[1].trim(); - mappedLine.put(field, value); - } - } - return mappedLine; + return linesInfo.stream() + .filter(mappedLine -> element.equals(mappedLine.get(ELEMENT_NAME))) + .findAny() + .map(found -> found.get(INTERNET_DB_ID)) + .orElse(null); } String formatTime(LocalDateTime time) { diff --git a/src/main/java/tv/mangrana/plex/url/PlexCommandLauncher.java b/src/main/java/tv/mangrana/plex/url/PlexCommandLauncher.java deleted file mode 100644 index a61715c..0000000 --- a/src/main/java/tv/mangrana/plex/url/PlexCommandLauncher.java +++ /dev/null @@ -1,119 +0,0 @@ -package tv.mangrana.plex.url; - -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.methods.RequestBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; -import tv.mangrana.config.CommonConfigFileLoader; -import tv.mangrana.utils.EasyLogger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; - -import static tv.mangrana.config.CommonConfigFileLoader.CommonProjectConfiguration.*; -import static tv.mangrana.utils.Output.log; -import static tv.mangrana.utils.rest.APIInterface.ProtocolURLMark.HTTPS; - -public class PlexCommandLauncher { - - private final EasyLogger logger; - private final CommonConfigFileLoader config; - private final PlexLibrarySectionsResolver sectionResolver; - - public PlexCommandLauncher(CommonConfigFileLoader config) { - this.config = config; - this.logger = new EasyLogger(); - this.sectionResolver = new PlexLibrarySectionsResolver(this); - } - -// public static void main(String[] args) throws IncorrectWorkingReferencesException { -// String toRefresh="/tv/Series/C/City on a Hill (2019)"; -// new PlexCommandLauncher(new CommonConfigFileLoader()).scanByPath(toRefresh); -// } - - boolean scanByPath(String plexPathToRefresh, String plexMountPath) { - boolean ok = true; - String plexRefreshURL = getPlexRefreshURL(plexPathToRefresh, plexMountPath); - if (plexRefreshURL==null) return false; - try (CloseableHttpClient httpclient = HttpClients.createDefault()) { - - HttpUriRequest httpGET = RequestBuilder.get() - .setUri(new URI(plexRefreshURL)) - .addParameter("path", plexPathToRefresh) - .addParameter("X-Plex-Token", config.getConfig(PLEX_TOKEN)) - .build(); - httpclient.execute(httpGET); - @SuppressWarnings("unused") - String urlWithTokenHidden = httpGET.getURI().toString().replaceFirst(config.getConfig(PLEX_TOKEN), "__plex_token__"); - logger.nLog("Launched URL command: {0}", httpGET.getURI().toString()); - } catch (Exception e) { - logger.nHLog("Some error has happened using the URL <{0}>", plexRefreshURL); - e.printStackTrace(); - ok = false; - } - return ok; - } - - public Document retrieveSectionsInfo() { - try (CloseableHttpClient httpclient = HttpClients.createDefault()) { - String plexSectionsURL = getPlexSectionsURL(); - HttpUriRequest httpGET = RequestBuilder.get() - .setUri(new URI(plexSectionsURL)) - .addParameter("X-Plex-Token", config.getConfig(PLEX_TOKEN)) - .build(); - - try (CloseableHttpResponse httpResponse = httpclient.execute(httpGET)) { - - final HttpEntity entity = httpResponse.getEntity(); - if (entity != null) { - try (InputStream inputStream = entity.getContent()) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - return builder.parse(inputStream); - } catch (ParserConfigurationException | SAXException e) { - log("could not get the section information from plex url"); - } - } - } - log("launched url command: "+httpGET.getURI().toString().replaceFirst(config.getConfig(PLEX_TOKEN), "__plex_token__")); - } catch (URISyntaxException | IOException e) { - log("could not refresh plex artist because of "+e.getMessage()); - e.printStackTrace(); - } - return null; - } - - private String getPlexRefreshURL(String fullDestinationPath, String plexMountPath) { - try { - String sectionId = sectionResolver.resolveSectionByPath(fullDestinationPath, plexMountPath); - if (sectionId==null) { - log("Could not resolve the section of the element in plex for "+fullDestinationPath); - return null; - } else { - log("Captured section <{0}> of the element in plex for {1}", sectionId, fullDestinationPath); - } - String host = config.getConfig(PLEX_HOST); - String uriFormat = config.getConfig(PLEX_SECTION_REFRESH_URI); - String uri = uriFormat.replaceFirst("\\{section_id}", sectionId); - return HTTPS.getMark() + host + uri; - } catch (Exception e) { - return null; - } - } - - private String getPlexSectionsURL() { - String host = HTTPS.getMark() + config.getConfig(PLEX_HOST); - String uri = config.getConfig(PLEX_SECTIONS_LIST_URI); - return host + uri; - } - -} diff --git a/src/main/java/tv/mangrana/plex/url/PlexLibrarySectionsResolver.java b/src/main/java/tv/mangrana/plex/url/PlexLibrarySectionsResolver.java deleted file mode 100644 index eecb1f1..0000000 --- a/src/main/java/tv/mangrana/plex/url/PlexLibrarySectionsResolver.java +++ /dev/null @@ -1,57 +0,0 @@ -package tv.mangrana.plex.url; - - -import com.sun.org.apache.xerces.internal.dom.DeferredElementImpl; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import tv.mangrana.config.CommonConfigFileLoader; -import tv.mangrana.utils.Output; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -public class PlexLibrarySectionsResolver { - - private final PlexCommandLauncher commandLauncher; - private Document sectionsInfo; - - public PlexLibrarySectionsResolver(PlexCommandLauncher commandLauncher) { - this.commandLauncher = commandLauncher; - } - - private void initSectionsIfNecessary() { - if (sectionsInfo==null) { - sectionsInfo = commandLauncher.retrieveSectionsInfo(); - } - } - - public String resolveSectionByPath(String fullDestinationPath, String plexMountPath) { - String keyFolder = fullDestinationPath.replaceFirst(plexMountPath,"").split("/")[1]; - initSectionsIfNecessary(); - XPath xPath = XPathFactory.newInstance().newXPath(); - String startingLocationText = plexMountPath.concat("/").concat(keyFolder).concat("/"); - String directoryNodeOfLocation = getDirectoryKeyValue(sectionsInfo, xPath, startingLocationText); - if (directoryNodeOfLocation == null) { - startingLocationText = plexMountPath.concat("/").concat(keyFolder); - //Output.log("but going to retry with {0}", startingLocationText); - return getDirectoryKeyValue(sectionsInfo, xPath, startingLocationText); - } else - return directoryNodeOfLocation; - } - - private String getDirectoryKeyValue(Document xmlDocument, XPath xPath, String startingLocationText) { - String expression = "/MediaContainer/Directory/Location[starts-with(@path, '"+ startingLocationText +"')]"; - try { - NodeList candidatesNodes = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); - Node directoryNodeOfLocation = candidatesNodes.item(0).getParentNode(); - return ((DeferredElementImpl) directoryNodeOfLocation).getAttribute("key"); - } catch (XPathExpressionException | NullPointerException e) { - //Output.log("could not resolve the section of the element in plex "+startingLocationText); - } - return null; - } - -} diff --git a/src/main/java/tv/mangrana/plex/url/PlexRefresher.java b/src/main/java/tv/mangrana/plex/url/PlexRefresher.java deleted file mode 100644 index 9f7d960..0000000 --- a/src/main/java/tv/mangrana/plex/url/PlexRefresher.java +++ /dev/null @@ -1,38 +0,0 @@ -package tv.mangrana.plex.url; - -import tv.mangrana.config.CommonConfigFileLoader; - -import static tv.mangrana.config.CommonConfigFileLoader.CommonProjectConfiguration.*; - -public class PlexRefresher { - - private final PlexCommandLauncher commandLauncher; - private final CommonConfigFileLoader config; - - public PlexRefresher(CommonConfigFileLoader config) { - this.commandLauncher = new PlexCommandLauncher(config); - this.config = config; - } - - public boolean scanSerieByPath(String fullDestinationPath) { - try { - String sonarrPathStarter = config.getConfig(SONARR_PATHS_STARTER); - String plexMountPath = config.getConfig(PLEX_SERIES_PATHS_STARTER); - String path2Refresh = fullDestinationPath.replaceFirst(sonarrPathStarter, plexMountPath); - return commandLauncher.scanByPath(path2Refresh, plexMountPath); - } catch (Exception e) { - return false; - } - } - - public boolean scanMovieByPath(String fullDestinationPath) { - try { - String radarrPathStarter = config.getConfig(RADARR_PATHS_STARTER); - String plexMountPath = config.getConfig(PLEX_MOVIES_PATHS_STARTER); - String pathToRefresh = fullDestinationPath.replaceFirst(radarrPathStarter, plexMountPath); - return commandLauncher.scanByPath(pathToRefresh, plexMountPath); - } catch (Exception e) { - return false; - } - } -} diff --git a/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrAPIInterface.java b/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrAPIInterface.java index 7946609..623d956 100644 --- a/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrAPIInterface.java +++ b/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrAPIInterface.java @@ -1,8 +1,9 @@ package tv.mangrana.radarr.api.client.gateway; import tv.mangrana.radarr.api.schema.command.RefreshMoviesCommand; +import tv.mangrana.radarr.api.schema.movie.Movie2Add; +import tv.mangrana.radarr.api.schema.movie.MovieFile; import tv.mangrana.radarr.api.schema.movie.MovieResource; -import tv.mangrana.radarr.api.schema.queue.Movie; import tv.mangrana.radarr.api.schema.queue.QueueResourcePagingResource; import tv.mangrana.utils.rest.APIInterface; @@ -34,7 +35,12 @@ public interface RadarrAPIInterface extends APIInterface { @GET @Path("/movie") @Produces({ MediaType.APPLICATION_JSON }) - List movieLookupByTMDBid(@QueryParam("tmdbId") int tmdbId, @QueryParam("apikey") String apikey); + List getMovieByTMDBid(@QueryParam("tmdbId") int tmdbId, @QueryParam("apikey") String apikey); + + @GET + @Path("/movie/lookup/tmdb") + @Produces({ MediaType.APPLICATION_JSON }) + MovieResource movieLookupByTMDBid(@QueryParam("tmdbId") int tmdbId, @QueryParam("apikey") String apikey); @POST @Path("/command") @@ -46,6 +52,26 @@ public interface RadarrAPIInterface extends APIInterface { @Consumes({ MediaType.APPLICATION_JSON }) void updateMovie(MovieResource movie, @PathParam("id") int movieId, @QueryParam("apikey") String apikey); + @POST + @Path("/movie") + @Consumes({ MediaType.APPLICATION_JSON }) + void addMovie(Movie2Add movie, @QueryParam("apikey") String apikey); + + @POST + @Path("/movie/import") + @Consumes({ MediaType.APPLICATION_JSON }) + void importMovie(MovieResource movie, @QueryParam("apikey") String apikey); + + @GET + @Path("/moviefile") + @Produces({ MediaType.APPLICATION_JSON }) + List getFileByMovieId(@QueryParam("movieId") int movieId, @QueryParam("apikey") String apikey); + + @PUT + @Path("/moviefile/{id}") + @Consumes({ MediaType.APPLICATION_JSON }) + void updateFile(MovieFile file, @PathParam("id") int fileId, @QueryParam("apikey") String apikey); + @PUT @Path("/movie/{id}") @Consumes({ MediaType.APPLICATION_JSON }) diff --git a/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrApiGateway.java b/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrApiGateway.java index 110eb32..b250f4d 100644 --- a/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrApiGateway.java +++ b/src/main/java/tv/mangrana/radarr/api/client/gateway/RadarrApiGateway.java @@ -1,25 +1,33 @@ package tv.mangrana.radarr.api.client.gateway; import tv.mangrana.config.CommonConfigFileLoader; +import tv.mangrana.exception.TooMuchTriesException; import tv.mangrana.radarr.api.schema.command.RefreshMoviesCommand; +import tv.mangrana.radarr.api.schema.movie.Movie2Add; +import tv.mangrana.radarr.api.schema.movie.MovieFile; import tv.mangrana.radarr.api.schema.movie.MovieResource; import tv.mangrana.radarr.api.schema.queue.QueueResourcePagingResource; +import tv.mangrana.utils.EasyLogger; +import tv.mangrana.utils.RetryEngine; +import tv.mangrana.utils.RetryEngine.Action; import tv.mangrana.utils.rest.APIProxyBuilderSingleton; import java.util.List; +import java.util.function.Supplier; import static tv.mangrana.config.CommonConfigFileLoader.CommonProjectConfiguration.RADARR_API_HOST; import static tv.mangrana.config.CommonConfigFileLoader.CommonProjectConfiguration.RADARR_API_KEY; -import static tv.mangrana.utils.Output.log; public class RadarrApiGateway { + protected final EasyLogger logger; private final String apiKey; private final RadarrAPIInterface proxy; public RadarrApiGateway(CommonConfigFileLoader config) { apiKey = config.getConfig(RADARR_API_KEY); proxy = APIProxyBuilderSingleton.getRadarrInterface(config.getConfig(RADARR_API_HOST)); + logger = new EasyLogger(); } public QueueResourcePagingResource getQueue() { @@ -28,33 +36,192 @@ public class RadarrApiGateway { public MovieResource getMovieById(Integer movieId) { MovieResource movie = proxy.getMovieById(movieId, apiKey); - log("retrieved movie from radarr with id "+movieId); + logger.nLog("retrieved movie from radarr with id "+movieId); return movie; } - public List movieLookupByTMDBid (int tmdbId) { - return proxy.movieLookupByTMDBid(tmdbId, apiKey); + public MovieResource getMovieByTMDBid (int tmdbId) throws TooMuchTriesException { + Supplier movieLookup = () -> { + try { + List retrieved = proxy.getMovieByTMDBid(tmdbId, apiKey); + if (!retrieved.isEmpty()) + return retrieved.get(0); + else return null; + } catch (Exception e) { + logger.nLog("failed movieLookupByTMDBid for {0}. Will be retried.", String.valueOf(tmdbId)); + e.printStackTrace(); + return null; + } + }; + return createMovieRetryer("MovieLookupByTMDBid") + .tryUntilGotDesired(movieLookup, 10); + } + + public MovieResource movieLookupByTMDBid (int tmdbId) throws TooMuchTriesException { + Supplier movieLookup = () -> { + try { + return proxy.movieLookupByTMDBid(tmdbId, apiKey); + } catch (Exception e) { + logger.nLog("failed movieLookupByTMDBid for {0}. Will be retried.", String.valueOf(tmdbId)); + e.printStackTrace(); + return null; + } + }; + RetryEngine retrier = new RetryEngine<>("MovieLookupByTMDBid", 2, logger::nLog); + return retrier.tryUntilGotDesired(movieLookup, 10); + } + + public boolean existMovieInRadarr(int tmdbId) throws TooMuchTriesException { + Supplier checkExistence = () -> { + try { + List retrieved = proxy.getMovieByTMDBid(tmdbId, apiKey); + return retrieved.isEmpty() ? Boolean.FALSE : Boolean.TRUE; + } catch (Exception e) { + logger.nLog("failed getMovieByTMDBid for {0}. Will be retried.", String.valueOf(tmdbId)); + e.printStackTrace(); + return null; + } + }; + return createPredicateRetryer("MovieLookupByTMDBid") + .tryUntilGotDesired(checkExistence, 10); } public void removeQueueItem(int itemId) { proxy.removeQueueItem(itemId, false, apiKey); - log("removed item from queue successfully: "+itemId); + logger.nLog("removed item from queue successfully: "+itemId); } - public void refreshMovie(int movieId) { - proxy.refreshMoviesCommand(new RefreshMoviesCommand(movieId), apiKey); - log("refreshed movie with id "+movieId); + public void refreshMovie(int movieId) throws TooMuchTriesException { + Supplier refresh = () -> { + try { + proxy.refreshMoviesCommand(new RefreshMoviesCommand(movieId), apiKey); + return Action.PERFORMED; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }; + createActionRetryer("RefreshMovie") + .tryUntilGotDesired(refresh, 10); + + logger.nLog("refreshed movie with id "+movieId); } - public void updateMovie(MovieResource movie){ - proxy.updateMovie(movie, movie.getId(), apiKey); + public void updateMovie(MovieResource movie) throws TooMuchTriesException { + Supplier refresh = () -> { + try { + proxy.updateMovie(movie, movie.getId(), apiKey); + return Action.PERFORMED; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }; + createActionRetryer("updateMovie") + .tryUntilGotDesired(refresh, 10); + + logger.nLog("updated movie in Radarr with id "+movie.getId()); } public void relocateMovie(MovieResource movie){ proxy.relocateMovie(movie, movie.getId(), true, apiKey); } - public List movieLookupByTitle (String title) { - return proxy.movieLookupByTitle(title, apiKey); + public MovieResource movieLookupByTitle (String title) throws TooMuchTriesException { + Supplier movieLookup = () -> { + try { + List retrieved = proxy.movieLookupByTitle(title, apiKey); + if (!retrieved.isEmpty()) + return retrieved.get(0); + else return null; + } catch (Exception e) { + logger.nLog("failed movieLookupByTitle for {0}. Will be retried.", title); + e.printStackTrace(); + return null; + } + }; + return createMovieRetryer("MovieLookupByTitle") + .tryUntilGotDesired(movieLookup, 10); } + + public void importMovie(MovieResource movie) throws TooMuchTriesException { + Supplier refresh = () -> { + try { + proxy.importMovie(movie, apiKey); + return Action.PERFORMED; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }; + createActionRetryer("addMovieMovie") + .tryUntilGotDesired(refresh, 10); + + logger.nLog("add movie in Radarr with id "+movie.getId()); + } + + public void addMovie(Movie2Add movie) { + proxy.addMovie(movie, apiKey); + } + + public MovieFile getFileByMovieId (int movieId) throws TooMuchTriesException { + Supplier movieLookup = () -> { + try { + List retrieved = proxy.getFileByMovieId(movieId, apiKey); + if (!retrieved.isEmpty()) + return retrieved.get(0); + else return null; + } catch (Exception e) { + logger.nLog("failed movieLookupByTitle for {0}. Will be retried.", String.valueOf(movieId)); + e.printStackTrace(); + return null; + } + }; + RetryEngine retryer = new RetryEngine<>("MovieLookupByTitle", 1, logger::nLog); + return retryer.tryUntilGotDesired(movieLookup, 10); + } + + public boolean existFileByMovieId (int movieId) throws TooMuchTriesException { + Supplier movieLookup = () -> { + try { + List retrieved = proxy.getFileByMovieId(movieId, apiKey); + return retrieved.isEmpty() ? Boolean.FALSE : Boolean.TRUE; + } catch (Exception e) { + logger.nLog("failed movieLookupByTitle for {0}. Will be retried.", String.valueOf(movieId)); + e.printStackTrace(); + return null; + } + }; + RetryEngine retryer = new RetryEngine<>("getFileByMovieId", 1, logger::nLog); + return retryer.tryUntilGotDesired(movieLookup, 10); + } + + public void updateFile(MovieFile file) throws TooMuchTriesException { + Supplier refresh = () -> { + try { + proxy.updateFile(file, file.getId(), apiKey); + return Action.PERFORMED; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + }; + createActionRetryer("updateMovie") + .tryUntilGotDesired(refresh, 10); + + logger.nLog("updated file in Radarr with id "+file.getId()); + } + + private RetryEngine createMovieRetryer(String title) { + return new RetryEngine<>(title,1,logger::nLog); + } + + private RetryEngine createActionRetryer(String title) { + return new RetryEngine<>(title,2,logger::nLog); + } + + private RetryEngine createPredicateRetryer(String title) { + return new RetryEngine<>(title,1,logger::nLog); + } + } diff --git a/src/main/java/tv/mangrana/radarr/api/schema/movie/MovieResource.java b/src/main/java/tv/mangrana/radarr/api/schema/movie/MovieResource.java index 835ae81..c460875 100644 --- a/src/main/java/tv/mangrana/radarr/api/schema/movie/MovieResource.java +++ b/src/main/java/tv/mangrana/radarr/api/schema/movie/MovieResource.java @@ -832,3 +832,4 @@ public class MovieResource { } } + diff --git a/src/main/java/tv/mangrana/utils/RetryEngine.java b/src/main/java/tv/mangrana/utils/RetryEngine.java index 55f0190..aa23449 100644 --- a/src/main/java/tv/mangrana/utils/RetryEngine.java +++ b/src/main/java/tv/mangrana/utils/RetryEngine.java @@ -36,6 +36,10 @@ public class RetryEngine { } } + public enum Action { + PERFORMED + } + public RetryEngine(String title, int minutesToWait, Consumer logger) { this(title, minutesToWait, null, logger); } diff --git a/src/main/java/tv/mangrana/utils/StringCaptor.java b/src/main/java/tv/mangrana/utils/StringCaptor.java index 8ad830c..fb8b30f 100644 --- a/src/main/java/tv/mangrana/utils/StringCaptor.java +++ b/src/main/java/tv/mangrana/utils/StringCaptor.java @@ -34,4 +34,11 @@ public class StringCaptor { return "Temporada ".concat(episodeInfo.substring(1,3)); } + public static int getTMDBFromFile(String path) throws IncorrectWorkingReferencesException { + String tmdbId = Optional.ofNullable( + StringCaptor.getMatchingSubstring(path.contains("/")?path.substring(path.lastIndexOf('/')):path, "\\{tmdb-(.*)\\}")) + .orElseThrow(() -> new IncorrectWorkingReferencesException("Couldn't find tmdb from: "+path)); + return Integer.parseInt(tmdbId); + } + }