mirror of
https://github.com/JasonHHouse/gaps.git
synced 2026-02-11 21:28:37 -06:00
Removing Gaps object
Switching URL creation from web to backend v0.1.1
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>Gaps</artifactId>
|
||||
<groupId>com.jasonhhouse</groupId>
|
||||
<version>0.1.0</version>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Jason H House
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Gaps {
|
||||
|
||||
private String movieDbApiKey;
|
||||
|
||||
private Boolean writeToFile;
|
||||
|
||||
private String movieDbListId;
|
||||
|
||||
private Boolean searchFromPlex;
|
||||
|
||||
private Integer connectTimeout;
|
||||
|
||||
private Integer writeTimeout;
|
||||
|
||||
private Integer readTimeout;
|
||||
|
||||
private List<String> movieUrls;
|
||||
|
||||
private Boolean searchFromFolder;
|
||||
|
||||
public Gaps() {
|
||||
}
|
||||
|
||||
public Gaps(String movieDbApiKey, Boolean writeToFile, String movieDbListId, Boolean searchFromPlex, Integer connectTimeout, Integer writeTimeout, Integer readTimeout, List<String> movieUrls, Boolean searchFromFolder) {
|
||||
this.movieDbApiKey = movieDbApiKey;
|
||||
this.writeToFile = writeToFile;
|
||||
this.movieDbListId = movieDbListId;
|
||||
this.searchFromPlex = searchFromPlex;
|
||||
this.connectTimeout = connectTimeout;
|
||||
this.writeTimeout = writeTimeout;
|
||||
this.readTimeout = readTimeout;
|
||||
this.movieUrls = movieUrls;
|
||||
this.searchFromFolder = searchFromFolder;
|
||||
}
|
||||
|
||||
public String getMovieDbApiKey() {
|
||||
return movieDbApiKey;
|
||||
}
|
||||
|
||||
public void setMovieDbApiKey(String movieDbApiKey) {
|
||||
this.movieDbApiKey = movieDbApiKey;
|
||||
}
|
||||
|
||||
public Boolean getWriteToFile() {
|
||||
return writeToFile;
|
||||
}
|
||||
|
||||
public void setWriteToFile(Boolean writeToFile) {
|
||||
this.writeToFile = writeToFile;
|
||||
}
|
||||
|
||||
public String getMovieDbListId() {
|
||||
return movieDbListId;
|
||||
}
|
||||
|
||||
public void setMovieDbListId(String movieDbListId) {
|
||||
this.movieDbListId = movieDbListId;
|
||||
}
|
||||
|
||||
public Boolean getSearchFromPlex() {
|
||||
return searchFromPlex;
|
||||
}
|
||||
|
||||
public void setSearchFromPlex(Boolean searchFromPlex) {
|
||||
this.searchFromPlex = searchFromPlex;
|
||||
}
|
||||
|
||||
public Integer getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(Integer connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public Integer getWriteTimeout() {
|
||||
return writeTimeout;
|
||||
}
|
||||
|
||||
public void setWriteTimeout(Integer writeTimeout) {
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public Integer getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public void setReadTimeout(Integer readTimeout) {
|
||||
this.readTimeout = readTimeout;
|
||||
}
|
||||
|
||||
public List<String> getMovieUrls() {
|
||||
return movieUrls;
|
||||
}
|
||||
|
||||
public void setMovieUrls(List<String> movieUrls) {
|
||||
this.movieUrls = movieUrls;
|
||||
}
|
||||
|
||||
public Boolean getSearchFromFolder() {
|
||||
return searchFromFolder;
|
||||
}
|
||||
|
||||
public void setSearchFromFolder(Boolean searchFromFolder) {
|
||||
this.searchFromFolder = searchFromFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Gaps gaps = (Gaps) o;
|
||||
return Objects.equals(movieDbApiKey, gaps.movieDbApiKey) &&
|
||||
Objects.equals(writeToFile, gaps.writeToFile) &&
|
||||
Objects.equals(movieDbListId, gaps.movieDbListId) &&
|
||||
Objects.equals(searchFromPlex, gaps.searchFromPlex) &&
|
||||
Objects.equals(connectTimeout, gaps.connectTimeout) &&
|
||||
Objects.equals(writeTimeout, gaps.writeTimeout) &&
|
||||
Objects.equals(readTimeout, gaps.readTimeout) &&
|
||||
Objects.equals(movieUrls, gaps.movieUrls) &&
|
||||
Objects.equals(searchFromFolder, gaps.searchFromFolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(movieDbApiKey, writeToFile, movieDbListId, searchFromPlex, connectTimeout, writeTimeout, readTimeout, movieUrls, searchFromFolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Gaps{" +
|
||||
"movieDbApiKey='" + movieDbApiKey + '\'' +
|
||||
", writeToFile=" + writeToFile +
|
||||
", movieDbListId='" + movieDbListId + '\'' +
|
||||
", searchFromPlex=" + searchFromPlex +
|
||||
", connectTimeout=" + connectTimeout +
|
||||
", writeTimeout=" + writeTimeout +
|
||||
", readTimeout=" + readTimeout +
|
||||
", movieUrls=" + movieUrls +
|
||||
", searchFromFolder=" + searchFromFolder +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface GapsSearch {
|
||||
|
||||
void run(@NotNull Gaps gaps);
|
||||
void run();
|
||||
|
||||
@NotNull Integer getTotalMovieCount();
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ RUN mkdir -p /usr/app
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
COPY GapsWeb/target/GapsWeb-0.1.0.jar /usr/app/
|
||||
COPY GapsWeb/target/GapsWeb-0.1.1.jar /usr/app/
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=no-ssl", "GapsWeb-0.1.0.jar"]
|
||||
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=no-ssl", "GapsWeb-0.1.1.jar"]
|
||||
@@ -12,6 +12,6 @@ RUN mkdir -p /usr/app
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
COPY GapsWeb/target/GapsWeb-0.1.0.jar /usr/app/
|
||||
COPY GapsWeb/target/GapsWeb-0.1.1.jar /usr/app/
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=ssl", "GapsWeb-0.1.0.jar"]
|
||||
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=ssl", "GapsWeb-0.1.1.jar"]
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>Gaps</artifactId>
|
||||
<groupId>com.jasonhhouse</groupId>
|
||||
<version>0.1.0</version>
|
||||
<version>0.1.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<dependency>
|
||||
<groupId>com.jasonhhouse</groupId>
|
||||
<artifactId>Core</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<version>0.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -9,21 +9,15 @@
|
||||
*/
|
||||
package com.jasonhhouse.gaps.controller;
|
||||
|
||||
import com.jasonhhouse.gaps.Gaps;
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
import com.jasonhhouse.gaps.Movie;
|
||||
import com.jasonhhouse.gaps.GapsService;
|
||||
import com.jasonhhouse.gaps.service.IoService;
|
||||
import java.util.List;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
@@ -54,67 +48,14 @@ public class SearchController {
|
||||
* Main REST call to start Gaps searching for missing movies
|
||||
*
|
||||
* @param gaps Needs the gaps object to get started with Plex information and TMDB key
|
||||
* @return All missing movies with their release year and collections associated to them
|
||||
*/
|
||||
@RequestMapping(value = "startSearching", method = RequestMethod.POST)
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public void postStartSearching(@RequestBody Gaps gaps) {
|
||||
LOGGER.info("postStartSearching( " + gaps + " )");
|
||||
public void postStartSearching() {
|
||||
LOGGER.info("postStartSearching( )");
|
||||
|
||||
ioService.migrateJsonSeedFileIfNeeded();
|
||||
|
||||
//Error checking
|
||||
if (StringUtils.isEmpty(gaps.getMovieDbApiKey())) {
|
||||
String reason = "Missing Movie DB Api Key. This field is required for Gaps.";
|
||||
LOGGER.error(reason);
|
||||
|
||||
Exception e = new IllegalArgumentException();
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason, e);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isNotTrue(gaps.getSearchFromPlex()) && BooleanUtils.isNotTrue(gaps.getSearchFromFolder())) {
|
||||
String reason = "Must search from Plex and/or folders. One or both of these fields is required for Gaps.";
|
||||
LOGGER.error(reason);
|
||||
|
||||
Exception e = new IllegalArgumentException();
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason, e);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isNotFalse(gaps.getSearchFromPlex())) {
|
||||
if (CollectionUtils.isEmpty(gaps.getMovieUrls())) {
|
||||
String reason = "Missing Plex movie collection urls. This field is required to search from Plex.";
|
||||
LOGGER.error(reason);
|
||||
|
||||
Exception e = new IllegalArgumentException();
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason, e);
|
||||
} else {
|
||||
for (String url : gaps.getMovieUrls()) {
|
||||
if (url == null) {
|
||||
String reason = "Found null Plex movie collection url. This field is required to search from Plex.";
|
||||
LOGGER.error(reason);
|
||||
Exception e = new IllegalArgumentException();
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Fill in default values if missing
|
||||
if (gaps.getWriteTimeout() == null) {
|
||||
LOGGER.info("Missing write timeout. Setting default to 180 seconds.");
|
||||
gaps.setWriteTimeout(180);
|
||||
}
|
||||
|
||||
if (gaps.getConnectTimeout() == null) {
|
||||
LOGGER.info("Missing connect timeout. Setting default to 180 seconds.");
|
||||
gaps.setConnectTimeout(180);
|
||||
}
|
||||
|
||||
if (gaps.getReadTimeout() == null) {
|
||||
LOGGER.info("Missing read timeout. Setting default to 180 seconds.");
|
||||
gaps.setReadTimeout(180);
|
||||
}
|
||||
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeType;
|
||||
import com.jasonhhouse.gaps.Gaps;
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
import com.jasonhhouse.gaps.GapsService;
|
||||
import com.jasonhhouse.gaps.Movie;
|
||||
import com.jasonhhouse.gaps.PlexLibrary;
|
||||
import com.jasonhhouse.gaps.SearchCancelledException;
|
||||
import com.jasonhhouse.gaps.SearchResults;
|
||||
import com.jasonhhouse.gaps.UrlGenerator;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@@ -31,6 +31,7 @@ import java.time.LocalDate;
|
||||
import java.time.Year;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -40,6 +41,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
@@ -53,7 +55,6 @@ import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -108,9 +109,12 @@ public class GapsSearchService implements GapsSearch {
|
||||
|
||||
private final IoService ioService;
|
||||
|
||||
private final GapsService gapsService;
|
||||
|
||||
@Autowired
|
||||
public GapsSearchService(@Qualifier("real") UrlGenerator urlGenerator, SimpMessagingTemplate template, IoService ioService) {
|
||||
public GapsSearchService(@Qualifier("real") UrlGenerator urlGenerator, SimpMessagingTemplate template, IoService ioService, GapsService gapsService) {
|
||||
this.template = template;
|
||||
this.gapsService = gapsService;
|
||||
this.ownedMovies = new HashSet<>();
|
||||
this.searched = new HashSet<>();
|
||||
this.recommended = new HashSet<>();
|
||||
@@ -126,8 +130,8 @@ public class GapsSearchService implements GapsSearch {
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void run(@NotNull Gaps gaps) {
|
||||
LOGGER.info("run( " + gaps + " )");
|
||||
public void run() {
|
||||
LOGGER.info("run( )");
|
||||
|
||||
searched.clear();
|
||||
ownedMovies.clear();
|
||||
@@ -138,43 +142,27 @@ public class GapsSearchService implements GapsSearch {
|
||||
searchedMovieCount.set(0);
|
||||
cancelSearch.set(false);
|
||||
|
||||
if (isGapsPropertyValid(gaps)) {
|
||||
String reason = "No search property defined. Must search from at least one type: Folder or Plex";
|
||||
cancelSearch.set(true);
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, reason);
|
||||
}
|
||||
|
||||
defaultValues(gaps);
|
||||
|
||||
try {
|
||||
String sessionId = null;
|
||||
// Get TMDB Authorization from user,
|
||||
// requires user input so needs to be done early before user walks away
|
||||
if (StringUtils.isNotEmpty(gaps.getMovieDbListId())) {
|
||||
sessionId = getTmdbAuthorization(gaps);
|
||||
}
|
||||
|
||||
if (BooleanUtils.isTrue(gaps.getSearchFromPlex())) {
|
||||
findAllPlexMovies(gaps);
|
||||
} else {
|
||||
LOGGER.info("Not searching from Plex");
|
||||
}
|
||||
|
||||
//ToDo
|
||||
/*if (properties.getFolder().getSearchFromFolder()) {
|
||||
findAllFolderMovies();
|
||||
}*/
|
||||
String sessionId = null;
|
||||
// // Get TMDB Authorization from user,
|
||||
// // requires user input so needs to be done early before user walks away
|
||||
//if (StringUtils.isNotEmpty(gaps.getMovieDbListId())) {
|
||||
// sessionId = getTmdbAuthorization(gaps);
|
||||
//}
|
||||
|
||||
findAllPlexMovies();
|
||||
|
||||
StopWatch watch = new StopWatch();
|
||||
watch.start();
|
||||
searchForMovies(gaps);
|
||||
searchForMovies();
|
||||
watch.stop();
|
||||
System.out.println("Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(watch.getTime()) + " seconds.");
|
||||
System.out.println("Times used TVDB ID: " + tempTvdbCounter);
|
||||
|
||||
if (StringUtils.isNotEmpty(gaps.getMovieDbListId())) {
|
||||
createTmdbList(gaps, sessionId);
|
||||
}
|
||||
/*if (StringUtils.isNotEmpty(gaps.getMovieDbListId())) {
|
||||
createTmdbList(sessionId);
|
||||
}*/
|
||||
|
||||
} catch (SearchCancelledException e) {
|
||||
String reason = "Search cancelled";
|
||||
@@ -185,9 +173,7 @@ public class GapsSearchService implements GapsSearch {
|
||||
cancelSearch.set(true);
|
||||
}
|
||||
|
||||
if (gaps.getWriteToFile()) {
|
||||
ioService.writeToFile(recommended);
|
||||
}
|
||||
ioService.writeToFile(recommended);
|
||||
|
||||
//Always write to log
|
||||
ioService.writeRecommendedToFile(recommended);
|
||||
@@ -196,28 +182,6 @@ public class GapsSearchService implements GapsSearch {
|
||||
template.convertAndSend("/finishedSearching", true);
|
||||
}
|
||||
|
||||
private boolean isGapsPropertyValid(Gaps gaps) {
|
||||
return BooleanUtils.isNotTrue(gaps.getSearchFromPlex()) && BooleanUtils.isNotTrue(gaps.getSearchFromFolder());
|
||||
}
|
||||
|
||||
private void defaultValues(Gaps gaps) {
|
||||
if (gaps.getConnectTimeout() == null) {
|
||||
gaps.setConnectTimeout(180);
|
||||
}
|
||||
|
||||
if (gaps.getReadTimeout() == null) {
|
||||
gaps.setReadTimeout(180);
|
||||
}
|
||||
|
||||
if (gaps.getWriteTimeout() == null) {
|
||||
gaps.setWriteTimeout(180);
|
||||
}
|
||||
|
||||
if (gaps.getWriteToFile() == null) {
|
||||
gaps.setWriteToFile(true);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Integer getTotalMovieCount() {
|
||||
@@ -251,78 +215,10 @@ public class GapsSearchService implements GapsSearch {
|
||||
return !cancelSearch.get();
|
||||
}
|
||||
|
||||
private void findAllFolderMovies() {
|
||||
//ToDo
|
||||
/*if (CollectionUtils.isEmpty(properties.getFolder().getFolders())) {
|
||||
LOGGER.error("folders property cannot be empty when searchFromFolder is true");
|
||||
return;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(properties.getFolder().getMovieFormats())) {
|
||||
LOGGER.error("movie formats property cannot be empty when searchFromFolder is true");
|
||||
return;
|
||||
}
|
||||
|
||||
for (String strFolder : properties.getFolder().getFolders()) {
|
||||
File folder = new File(strFolder);
|
||||
searchFolders(folder);
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
private void searchFolders(File folder) {
|
||||
//ToDo
|
||||
/*if (!folder.exists()) {
|
||||
LOGGER.warn("Folder in folders property does not exist: " + folder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folder.isDirectory()) {
|
||||
LOGGER.warn("Folder in folders property is not a directory: " + folder);
|
||||
return;
|
||||
}
|
||||
|
||||
File[] files = folder.listFiles();
|
||||
if (files == null) {
|
||||
LOGGER.warn("Folder in folders property is empty: " + folder);
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
if (file.isDirectory() && properties.getFolder().getRecursive()) {
|
||||
searchFolders(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
String extension = FilenameUtils.getExtension(file.toString());
|
||||
|
||||
if (properties.getFolder().getMovieFormats().contains(extension)) {
|
||||
String fullMovie = FilenameUtils.getBaseName(file.toString());
|
||||
Pattern pattern = Pattern.compile(properties.getFolder().getYearRegex());
|
||||
Matcher matcher = pattern.matcher(fullMovie);
|
||||
|
||||
if (!matcher.find()) {
|
||||
LOGGER.warn("No regex matches found for " + fullMovie);
|
||||
continue;
|
||||
}
|
||||
|
||||
String year = matcher.group(matcher.groupCount()).replaceAll("[)(]", "");
|
||||
String title = fullMovie.substring(0, fullMovie.indexOf(" ("));
|
||||
|
||||
Movie movie = new Movie(-1, title, Integer.parseInt(year), "");
|
||||
ownedMovies.add(movie);
|
||||
} else {
|
||||
LOGGER.warn("Skipping file " + file);
|
||||
}
|
||||
|
||||
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Using TMDB api (V3), get access to user list and add recommended movies to
|
||||
*/
|
||||
private @Nullable String getTmdbAuthorization(@NotNull Gaps gaps) {
|
||||
private @Nullable String getTmdbAuthorization() {
|
||||
// Create the request_token request
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
@@ -333,7 +229,7 @@ public class GapsSearchService implements GapsSearch {
|
||||
.addPathSegment("authentication")
|
||||
.addPathSegment("token")
|
||||
.addPathSegment("new")
|
||||
.addQueryParameter("api_key", gaps.getMovieDbApiKey())
|
||||
.addQueryParameter("api_key", gapsService.getPlexSearch().getMovieDbApiKey())
|
||||
.build();
|
||||
|
||||
MediaType mediaType = MediaType.parse("application/octet-stream");
|
||||
@@ -370,7 +266,7 @@ public class GapsSearchService implements GapsSearch {
|
||||
.addPathSegment("authentication")
|
||||
.addPathSegment("session")
|
||||
.addPathSegment("new")
|
||||
.addQueryParameter("api_key", gaps.getMovieDbApiKey())
|
||||
.addQueryParameter("api_key", gapsService.getPlexSearch().getMovieDbApiKey())
|
||||
.build();
|
||||
|
||||
// Create the sesssion ID for MovieDB using the approved token
|
||||
@@ -395,7 +291,8 @@ public class GapsSearchService implements GapsSearch {
|
||||
/**
|
||||
* Using TMDB api (V3), get access to user list and add recommended movies to
|
||||
*/
|
||||
private void createTmdbList(@NotNull Gaps gaps, @Nullable String sessionId) {
|
||||
//ToDo
|
||||
/* private void createTmdbList(@Nullable String sessionId) {
|
||||
OkHttpClient client;
|
||||
MediaType mediaType = MediaType.parse("application/json");
|
||||
RequestBody body;
|
||||
@@ -436,20 +333,22 @@ public class GapsSearchService implements GapsSearch {
|
||||
}
|
||||
}
|
||||
LOGGER.info(counter + " Movies added to list. \nList located at: https://www.themoviedb.org/list/" + gaps.getMovieDbListId());
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Connect to plex via the URL and parse all of the movies from the returned XML creating a HashSet of movies the
|
||||
* user has.
|
||||
*/
|
||||
private void findAllPlexMovies(@NotNull Gaps gaps) throws SearchCancelledException {
|
||||
LOGGER.info("findAllPlexMovies( " + gaps + " )");
|
||||
private void findAllPlexMovies() throws SearchCancelledException {
|
||||
LOGGER.info("findAllPlexMovies( )");
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(gaps.getConnectTimeout(), TimeUnit.SECONDS)
|
||||
.writeTimeout(gaps.getWriteTimeout(), TimeUnit.SECONDS)
|
||||
.readTimeout(gaps.getReadTimeout(), TimeUnit.SECONDS)
|
||||
.connectTimeout(180, TimeUnit.SECONDS)
|
||||
.writeTimeout(180, TimeUnit.SECONDS)
|
||||
.readTimeout(180, TimeUnit.SECONDS)
|
||||
.build();
|
||||
List<String> urls = gaps.getMovieUrls();
|
||||
|
||||
|
||||
List<String> urls = generatePlexUrls();
|
||||
|
||||
if (CollectionUtils.isEmpty(urls)) {
|
||||
LOGGER.info("No URLs added to plexMovieUrls. Check your application.yaml file if needed.");
|
||||
@@ -567,11 +466,11 @@ public class GapsSearchService implements GapsSearch {
|
||||
* optimize some network calls, we add movies found in a collection and in plex to our already searched list, so we
|
||||
* don't re-query collections again and again.
|
||||
*/
|
||||
private void searchForMovies(@NotNull Gaps gaps) throws SearchCancelledException {
|
||||
private void searchForMovies() throws SearchCancelledException {
|
||||
LOGGER.info("Searching for Movie Collections...");
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
if (StringUtils.isEmpty(gaps.getMovieDbApiKey())) {
|
||||
if (StringUtils.isEmpty(gapsService.getPlexSearch().getMovieDbApiKey())) {
|
||||
LOGGER.error("No MovieDb Key added to movieDbApiKey. Need to submit movieDbApiKey on each request.");
|
||||
return;
|
||||
}
|
||||
@@ -601,19 +500,19 @@ public class GapsSearchService implements GapsSearch {
|
||||
if (movie.getTvdbId() != -1 && movie.getCollectionId() != -1) {
|
||||
LOGGER.debug("Used Collection ID to get " + movie.getName());
|
||||
tempTvdbCounter.incrementAndGet();
|
||||
handleCollection(gaps, movie, client);
|
||||
handleCollection(movie, client);
|
||||
continue;
|
||||
} else if (movie.getTvdbId() != -1) {
|
||||
LOGGER.debug("Used TVDB ID to get " + movie.getName());
|
||||
tempTvdbCounter.incrementAndGet();
|
||||
searchMovieDetails(gaps, movie, client);
|
||||
searchMovieDetails(movie, client);
|
||||
continue;
|
||||
} else if (StringUtils.isNotBlank(movie.getImdbId())) {
|
||||
LOGGER.debug("Used 'find' to search for " + movie.getName());
|
||||
searchMovieUrl = urlGenerator.generateFindMovieUrl(gaps.getMovieDbApiKey(), URLEncoder.encode(movie.getImdbId(), "UTF-8"));
|
||||
searchMovieUrl = urlGenerator.generateFindMovieUrl(gapsService.getPlexSearch().getMovieDbApiKey(), URLEncoder.encode(movie.getImdbId(), "UTF-8"));
|
||||
} else {
|
||||
LOGGER.debug("Used 'search' to search for " + movie.getName());
|
||||
searchMovieUrl = urlGenerator.generateSearchMovieUrl(gaps.getMovieDbApiKey(), URLEncoder.encode(movie.getName(), "UTF-8"), String.valueOf(movie.getYear()));
|
||||
searchMovieUrl = urlGenerator.generateSearchMovieUrl(gapsService.getPlexSearch().getMovieDbApiKey(), URLEncoder.encode(movie.getName(), "UTF-8"), String.valueOf(movie.getYear()));
|
||||
}
|
||||
|
||||
Request request = new Request.Builder()
|
||||
@@ -670,7 +569,7 @@ public class GapsSearchService implements GapsSearch {
|
||||
everyMovie.add(newMovie);
|
||||
}
|
||||
|
||||
searchMovieDetails(gaps, movie, client);
|
||||
searchMovieDetails(movie, client);
|
||||
} catch (JsonProcessingException e) {
|
||||
LOGGER.error("Error parsing movie " + movie + ". " + e.getMessage());
|
||||
LOGGER.error("URL: " + searchMovieUrl);
|
||||
@@ -703,8 +602,8 @@ public class GapsSearchService implements GapsSearch {
|
||||
}
|
||||
}
|
||||
|
||||
private void searchMovieDetails(Gaps gaps, Movie movie, OkHttpClient client) {
|
||||
HttpUrl movieDetailUrl = urlGenerator.generateMovieDetailUrl(gaps.getMovieDbApiKey(), String.valueOf(movie.getImdbId()));
|
||||
private void searchMovieDetails(Movie movie, OkHttpClient client) {
|
||||
HttpUrl movieDetailUrl = urlGenerator.generateMovieDetailUrl(gapsService.getPlexSearch().getMovieDbApiKey(), String.valueOf(movie.getImdbId()));
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(movieDetailUrl)
|
||||
@@ -748,15 +647,15 @@ public class GapsSearchService implements GapsSearch {
|
||||
everyMovie.add(newMovie);
|
||||
}
|
||||
|
||||
handleCollection(gaps, movie, client);
|
||||
handleCollection(movie, client);
|
||||
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Error getting movie details " + movie, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCollection(Gaps gaps, Movie movie, OkHttpClient client) {
|
||||
HttpUrl collectionUrl = urlGenerator.generateCollectionUrl(gaps.getMovieDbApiKey(), String.valueOf(movie.getCollectionId()));
|
||||
private void handleCollection(Movie movie, OkHttpClient client) {
|
||||
HttpUrl collectionUrl = urlGenerator.generateCollectionUrl(gapsService.getPlexSearch().getMovieDbApiKey(), String.valueOf(movie.getCollectionId()));
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(collectionUrl)
|
||||
@@ -839,7 +738,7 @@ public class GapsSearchService implements GapsSearch {
|
||||
sendEmptySearchUpdate();
|
||||
} else if (!searched.contains(movieFromCollection) && year != 0 && year < Year.now().getValue()) {
|
||||
// Get recommended Movie details from MovieDB API
|
||||
HttpUrl movieDetailUrl = urlGenerator.generateMovieDetailUrl(gaps.getMovieDbApiKey(), String.valueOf(movieFromCollection.getTvdbId()));
|
||||
HttpUrl movieDetailUrl = urlGenerator.generateMovieDetailUrl(gapsService.getPlexSearch().getMovieDbApiKey(), String.valueOf(movieFromCollection.getTvdbId()));
|
||||
|
||||
Request newReq = new Request.Builder()
|
||||
.url(movieDetailUrl)
|
||||
@@ -939,4 +838,16 @@ public class GapsSearchService implements GapsSearch {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<String> generatePlexUrls() {
|
||||
LOGGER.info(gapsService.getPlexSearch().getLibraries().toString());
|
||||
List<String> urls = gapsService.getPlexSearch()
|
||||
.getLibraries()
|
||||
.stream()
|
||||
.filter(PlexLibrary::getSelected)
|
||||
.map(plexLibrary -> "http://" + gapsService.getPlexSearch().getAddress() + ":" + gapsService.getPlexSearch().getPort() + "/library/sections/" + plexLibrary.getKey() + "/all/?X-Plex-Token=" + gapsService.getPlexSearch().getPlexToken())
|
||||
.collect(Collectors.toList());
|
||||
LOGGER.info("URLS: " + urls.size());
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ package com.jasonhhouse.gaps.service;
|
||||
import com.jasonhhouse.gaps.GapsService;
|
||||
import com.jasonhhouse.gaps.PlexLibrary;
|
||||
import com.jasonhhouse.gaps.PlexSearch;
|
||||
import com.jasonhhouse.gaps.controller.PlexMovieListController;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -43,7 +41,18 @@ public class GapsServiceImpl implements GapsService {
|
||||
@Override
|
||||
public void updateLibrarySelections(@NotNull List<PlexLibrary> plexLibraries) {
|
||||
LOGGER.info("updateLibrarySelections( " + plexLibraries + " )");
|
||||
getPlexSearch().getLibraries().addAll(plexLibraries.stream().filter(PlexLibrary::getSelected).collect(Collectors.toList()));
|
||||
LOGGER.info("BEFORE:" + getPlexSearch().getLibraries().toString());
|
||||
for (PlexLibrary plexLibrary : plexLibraries) {
|
||||
int index = getPlexSearch().getLibraries().indexOf(plexLibrary);
|
||||
LOGGER.info("Index of plexLibrary: " + index + " - " + plexLibrary);
|
||||
if (index == -1) {
|
||||
getPlexSearch().getLibraries().add(plexLibrary);
|
||||
} else {
|
||||
getPlexSearch().getLibraries().get(index).setSelected(plexLibrary.getSelected());
|
||||
}
|
||||
|
||||
}
|
||||
LOGGER.info("AFTER:" + getPlexSearch().getLibraries().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PlexLibrariesValidator implements Validator {
|
||||
}
|
||||
|
||||
if (plexLibrary.getSelected() == null) {
|
||||
errors.rejectValue("libraries", "plexLibrary.selected().empty");
|
||||
plexLibrary.setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ info:
|
||||
app:
|
||||
name: Gaps
|
||||
description: Gaps searches through your Plex Server or local folders for all movies, then queries for known movies in the same collection. If those movies don't exist in your library, Gaps will recommend getting those movies, legally of course.
|
||||
version: 0.1.0
|
||||
version: 0.1.1
|
||||
|
||||
---
|
||||
spring:
|
||||
@@ -79,5 +79,5 @@ info:
|
||||
app:
|
||||
name: Gaps
|
||||
description: Gaps searches through your Plex Server or local folders for all movies, then queries for known movies in the same collection. If those movies don't exist in your library, Gaps will recommend getting those movies, legally of course.
|
||||
version: 0.1.0
|
||||
version: 0.1.1
|
||||
|
||||
|
||||
@@ -129,31 +129,9 @@ function search() {
|
||||
searchTitle.text("Searching for Movies");
|
||||
searchDescription.text("Gaps is looking through your Plex libraries. This could take a while so just sit tight, and we'll find all the missing movies for you.");
|
||||
|
||||
const plexSearch = JSON.parse($('#plexSearch').val());
|
||||
|
||||
let plexMovieUrls = [];
|
||||
|
||||
plexSearch.libraries.forEach(function (library) {
|
||||
let data = {
|
||||
'X-Plex-Token': plexSearch.plexToken
|
||||
};
|
||||
|
||||
let encoded = encodeQueryData(data);
|
||||
let plexMovieUrl = `http://${plexSearch.address}:${plexSearch.port}/library/sections/${library.key}/all/?${encoded}`;
|
||||
plexMovieUrls.push(plexMovieUrl);
|
||||
});
|
||||
|
||||
const gaps = {
|
||||
movieDbApiKey: plexSearch.movieDbApiKey,
|
||||
writeToFile: true,
|
||||
searchFromPlex: true,
|
||||
movieUrls: plexMovieUrls
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "startSearching",
|
||||
data: JSON.stringify(gaps),
|
||||
contentType: "application/json"
|
||||
});
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col l6 s12">
|
||||
<h5 class="white-text">Gaps v0.1.0</h5>
|
||||
<h5 class="white-text">Gaps v0.1.1</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="container">
|
||||
|
||||
<h2 class="top-margin">Welcome to Gaps</h2>
|
||||
<h4 class="top-margin">v0.1.0</h4>
|
||||
<h4 class="top-margin">v0.1.1</h4>
|
||||
|
||||
<p>Gaps searches through your Plex Server. It then queries
|
||||
for known
|
||||
|
||||
@@ -29,10 +29,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@SpringBootTest(classes = GapsApplication.class)
|
||||
class GapsSearchServiceTest {
|
||||
|
||||
private final Gaps gaps = new Gaps();
|
||||
private GapsUrlGeneratorTest gapsUrlGeneratorTest;
|
||||
private GapsSearchService gapsSearch;
|
||||
|
||||
@Mock
|
||||
private GapsService gapsService;
|
||||
|
||||
@Mock
|
||||
private IoService ioService;
|
||||
|
||||
@@ -40,7 +42,7 @@ class GapsSearchServiceTest {
|
||||
void setup() throws Exception {
|
||||
gapsUrlGeneratorTest = new GapsUrlGeneratorTest();
|
||||
SimpMessagingTemplate template = new SimpMessagingTemplate((message, l) -> true);
|
||||
gapsSearch = new GapsSearchService(gapsUrlGeneratorTest, template, ioService);
|
||||
gapsSearch = new GapsSearchService(gapsUrlGeneratorTest, template, ioService, gapsService);
|
||||
|
||||
// Create a MockWebServer. These are lean enough that you can create a new
|
||||
// instance for every unit test.
|
||||
@@ -68,14 +70,13 @@ class GapsSearchServiceTest {
|
||||
@Test
|
||||
void emptyGapsProperty() {
|
||||
Assertions.assertThrows(ResponseStatusException.class, () -> {
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
}, "Should throw exception when not searching from folder and Plex");
|
||||
}
|
||||
|
||||
@Test
|
||||
void searchPlexGapsEmptyOtherwise() throws Exception {
|
||||
gaps.setSearchFromPlex(true);
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
|
||||
List<Movie> recommended = gapsSearch.getRecommendedMovies();
|
||||
Assertions.assertEquals(recommended.size(), 0, "Shouldn't have found any movies");
|
||||
@@ -133,11 +134,7 @@ class GapsSearchServiceTest {
|
||||
List<String> movieUrls = new ArrayList<>();
|
||||
movieUrls.add(GapsUrlGeneratorTest.PLEX_EMPTY_URL);
|
||||
|
||||
gaps.setMovieUrls(movieUrls);
|
||||
gaps.setSearchFromPlex(true);
|
||||
gaps.setWriteToFile(false);
|
||||
|
||||
Assertions.assertThrows(ResponseStatusException.class, () -> gapsSearch.run(gaps), "Should throw exception that the body was empty");
|
||||
Assertions.assertThrows(ResponseStatusException.class, () -> gapsSearch.run(), "Should throw exception that the body was empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,11 +144,7 @@ class GapsSearchServiceTest {
|
||||
List<String> movieUrls = new ArrayList<>();
|
||||
movieUrls.add(GapsUrlGeneratorTest.NO_MOVIE_PLEX_URL);
|
||||
|
||||
gaps.setMovieUrls(movieUrls);
|
||||
gaps.setSearchFromPlex(true);
|
||||
gaps.setWriteToFile(false);
|
||||
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
|
||||
List<Movie> recommended = gapsSearch.getRecommendedMovies();
|
||||
Assertions.assertEquals(recommended.size(), 0, "Shouldn't have found any movies");
|
||||
@@ -164,11 +157,7 @@ class GapsSearchServiceTest {
|
||||
List<String> movieUrls = new ArrayList<>();
|
||||
movieUrls.add(GapsUrlGeneratorTest.EMPTY_MOVIE_PLEX_URL);
|
||||
|
||||
gaps.setMovieUrls(movieUrls);
|
||||
gaps.setSearchFromPlex(true);
|
||||
gaps.setWriteToFile(false);
|
||||
|
||||
Assertions.assertThrows(ResponseStatusException.class, () -> gapsSearch.run(gaps), "Should throw exception that the title was missing from the video element");
|
||||
Assertions.assertThrows(ResponseStatusException.class, () -> gapsSearch.run(), "Should throw exception that the title was missing from the video element");
|
||||
}
|
||||
|
||||
|
||||
@@ -179,11 +168,7 @@ class GapsSearchServiceTest {
|
||||
List<String> movieUrls = new ArrayList<>();
|
||||
movieUrls.add(GapsUrlGeneratorTest.PLEX_WITH_GUID_URL);
|
||||
|
||||
gaps.setMovieUrls(movieUrls);
|
||||
gaps.setSearchFromPlex(true);
|
||||
gaps.setWriteToFile(false);
|
||||
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
assertEquals(gapsSearch.getTotalMovieCount(), 1, "Should have found exactly one movie");
|
||||
}
|
||||
|
||||
@@ -193,12 +178,7 @@ class GapsSearchServiceTest {
|
||||
|
||||
List<String> movieUrls = new ArrayList<>();
|
||||
movieUrls.add(GapsUrlGeneratorTest.PLEX_MOVIE_URL);
|
||||
|
||||
gaps.setMovieUrls(movieUrls);
|
||||
gaps.setSearchFromPlex(true);
|
||||
gaps.setWriteToFile(false);
|
||||
|
||||
gapsSearch.run(gaps);
|
||||
gapsSearch.run();
|
||||
assertEquals(gapsSearch.getTotalMovieCount(), 1, "Should have found exactly one movie");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mvn clean install
|
||||
docker build -f Dockerfile.ssl -t housewrecker/gaps:latest .
|
||||
docker push housewrecker/gaps:latest
|
||||
docker build -f Dockerfile.no-ssl -t housewrecker/gaps:latest-no-ssl .
|
||||
docker push housewrecker/gaps:latest-no-ssl
|
||||
mvn clean install -DskipTests
|
||||
docker build -f Dockerfile.ssl -t housewrecker/gaps:v0.1.1 .
|
||||
docker push housewrecker/gaps:v0.1.1
|
||||
docker build -f Dockerfile.no-ssl -t housewrecker/gaps:v0.1.1-no-ssl .
|
||||
docker push housewrecker/gaps:v0.1.1-no-ssl
|
||||
Reference in New Issue
Block a user