mirror of
https://github.com/JasonHHouse/gaps.git
synced 2026-02-13 06:09:16 -06:00
Merge pull request #75 from JasonHHouse/improvement/health_check_and_controller_break_up
Improvement/health check and controller break up
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;/*
|
||||
package com.jasonhhouse.gaps;/*
|
||||
* Copyright 2019 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:
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;/*
|
||||
package com.jasonhhouse.gaps;/*
|
||||
* Copyright 2019 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:
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;/*
|
||||
package com.jasonhhouse.gaps;/*
|
||||
* Copyright 2019 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:
|
||||
@@ -33,15 +33,15 @@ public final class Movie implements Comparable<Movie> {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
Movie(String imdbId, String name, int year, String collection) {
|
||||
public Movie(String imdbId, String name, int year, String collection) {
|
||||
this(-1, imdbId, name, year, collection);
|
||||
}
|
||||
|
||||
Movie(int tvdbId, String name, int year, String collection) {
|
||||
public Movie(int tvdbId, String name, int year, String collection) {
|
||||
this(-1, null, name, year, collection);
|
||||
}
|
||||
|
||||
Movie(String name, int year, String collection) {
|
||||
public Movie(String name, int year, String collection) {
|
||||
this(-1, name, year, collection);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;/*
|
||||
package com.jasonhhouse.gaps;/*
|
||||
* Copyright 2019 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:
|
||||
@@ -8,9 +8,8 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class SearchResults {
|
||||
@@ -12,7 +12,7 @@
|
||||
<artifactId>GapsWeb</artifactId>
|
||||
|
||||
<properties>
|
||||
<start-class>com.jasonhhouse.Gaps.GapsApplication</start-class>
|
||||
<start-class>com.jasonhhouse.gaps.GapsApplication</start-class>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -136,6 +136,11 @@
|
||||
<version>17.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
@@ -188,7 +193,7 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>com.jasonhhouse.Gaps.GapsApplication</mainClass>
|
||||
<mainClass>com.jasonhhouse.gaps.GapsApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
@@ -8,17 +8,15 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import java.util.concurrent.Executor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Search for all missing movies in your plex collection by MovieDB collection.
|
||||
*/
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
public class SearchCancelledException extends Exception {
|
||||
public SearchCancelledException() {
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -8,7 +8,7 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.jasonhhouse.gaps.controller;
|
||||
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "cancelSearch")
|
||||
public class CancelController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(CancelController.class);
|
||||
|
||||
private final GapsSearch gapsSearch;
|
||||
|
||||
@Autowired
|
||||
CancelController(GapsSearch gapsSearch) {
|
||||
this.gapsSearch = gapsSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a stop to searching. Used commonly if navigated away from page.
|
||||
*
|
||||
* @return success of search canceled
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.PUT)
|
||||
public ResponseEntity<String> cancelSearch() {
|
||||
logger.info("cancelSearch()");
|
||||
gapsSearch.cancelSearch();
|
||||
return new ResponseEntity<>("Canceled Search", HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2019 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.controller;
|
||||
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
import com.jasonhhouse.gaps.PlexLibrary;
|
||||
import java.util.Set;
|
||||
import okhttp3.HttpUrl;
|
||||
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.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
/**
|
||||
* Handles REST and WebSocket calls for Gaps.
|
||||
*/
|
||||
@Controller
|
||||
public class PlexController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PlexController.class);
|
||||
|
||||
private final GapsSearch gapsSearch;
|
||||
|
||||
@Autowired
|
||||
PlexController(GapsSearch gapsSearch) {
|
||||
this.gapsSearch = gapsSearch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches Plex for the "Movie" libraries it can find
|
||||
*
|
||||
* @param address Host name of the machine to connect to Plex on
|
||||
* @param port Port Plex runs on
|
||||
* @param token User specific Plex token
|
||||
* @return List of PlexLibraries found
|
||||
*/
|
||||
@RequestMapping(value = "getPlexLibraries", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Set<PlexLibrary>> getPlexLibraries(@RequestParam("address") String address,
|
||||
@RequestParam("port") int port,
|
||||
@RequestParam("token") String token) {
|
||||
logger.info("getPlexLibraries()");
|
||||
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
String reason = "Plex token cannot be empty";
|
||||
logger.error(reason);
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason);
|
||||
}
|
||||
|
||||
HttpUrl url = new HttpUrl.Builder()
|
||||
.scheme("http")
|
||||
.host(address)
|
||||
.port(port)
|
||||
.addPathSegment("library")
|
||||
.addPathSegment("sections")
|
||||
.addQueryParameter("X-Plex-Token", token)
|
||||
.build();
|
||||
|
||||
Set<PlexLibrary> plexLibraries = gapsSearch.getPlexLibraries(url);
|
||||
return new ResponseEntity<>(plexLibraries, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
/*
|
||||
* Copyright 2019 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;
|
||||
package com.jasonhhouse.gaps.controller;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import com.jasonhhouse.gaps.Gaps;
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
import com.jasonhhouse.gaps.Movie;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -18,77 +13,23 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Handles REST and WebSocket calls for Gaps.
|
||||
*/
|
||||
@Controller
|
||||
public class GapsControllerImpl {
|
||||
public class TmdbController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GapsControllerImpl.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(TmdbController.class);
|
||||
|
||||
private final GapsSearch gapsSearch;
|
||||
private final SimpMessagingTemplate template;
|
||||
|
||||
@Autowired
|
||||
GapsControllerImpl(GapsSearch gapsSearch, SimpMessagingTemplate template) {
|
||||
TmdbController(GapsSearch gapsSearch) {
|
||||
this.gapsSearch = gapsSearch;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches Plex for the "Movie" libraries it can find
|
||||
*
|
||||
* @param address Host name of the machine to connect to Plex on
|
||||
* @param port Port Plex runs on
|
||||
* @param token User specific Plex token
|
||||
* @return List of PlexLibraries found
|
||||
*/
|
||||
@RequestMapping(value = "getPlexLibraries", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public ResponseEntity<Set<PlexLibrary>> getPlexLibraries(@RequestParam("address") String address,
|
||||
@RequestParam("port") int port,
|
||||
@RequestParam("token") String token) {
|
||||
logger.info("getPlexLibraries()");
|
||||
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
String reason = "Plex token cannot be empty";
|
||||
logger.error(reason);
|
||||
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY, reason);
|
||||
}
|
||||
|
||||
HttpUrl url = new HttpUrl.Builder()
|
||||
.scheme("http")
|
||||
.host(address)
|
||||
.port(port)
|
||||
.addPathSegment("library")
|
||||
.addPathSegment("sections")
|
||||
.addQueryParameter("X-Plex-Token", token)
|
||||
.build();
|
||||
|
||||
Set<PlexLibrary> plexLibraries = gapsSearch.getPlexLibraries(url);
|
||||
return new ResponseEntity<>(plexLibraries, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a stop to searching. Used commonly if navigated away from page.
|
||||
*
|
||||
* @return success of search canceled
|
||||
*/
|
||||
@RequestMapping(value = "cancelSearch", method = RequestMethod.PUT)
|
||||
public ResponseEntity<String> cancelSearch() {
|
||||
logger.info("cancelSearch()");
|
||||
gapsSearch.cancelSearch();
|
||||
return new ResponseEntity<>("Canceled Search", HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,5 +98,4 @@ public class GapsControllerImpl {
|
||||
|
||||
return gapsSearch.run(gaps);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,15 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps.service;
|
||||
|
||||
import com.jasonhhouse.gaps.Gaps;
|
||||
import com.jasonhhouse.gaps.GapsSearch;
|
||||
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.FileNotFoundException;
|
||||
@@ -67,9 +74,9 @@ import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@Service
|
||||
public class GapsSearchBean implements GapsSearch {
|
||||
public class GapsSearchService implements GapsSearch {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GapsSearchBean.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(GapsSearchService.class);
|
||||
|
||||
private final Set<Movie> searched;
|
||||
|
||||
@@ -88,7 +95,7 @@ public class GapsSearchBean implements GapsSearch {
|
||||
private final SimpMessagingTemplate template;
|
||||
|
||||
@Autowired
|
||||
public GapsSearchBean(@Qualifier("real") UrlGenerator urlGenerator, SimpMessagingTemplate template) {
|
||||
public GapsSearchService(@Qualifier("real") UrlGenerator urlGenerator, SimpMessagingTemplate template) {
|
||||
this.template = template;
|
||||
this.ownedMovies = new HashSet<>();
|
||||
this.searched = new HashSet<>();
|
||||
@@ -43,4 +43,10 @@ server:
|
||||
key-store-password: gapsgapsgaps
|
||||
key-alias: gaps
|
||||
security:
|
||||
require-ssl: true
|
||||
require-ssl: true
|
||||
|
||||
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.0.5
|
||||
@@ -117,6 +117,7 @@ function search() {
|
||||
searchPosition.html('');
|
||||
backButton.text('restart');
|
||||
setCopyToClipboardEnabled(true);
|
||||
disconnect();
|
||||
},
|
||||
error: function (err) {
|
||||
disconnect();
|
||||
@@ -153,7 +154,6 @@ function connect() {
|
||||
stompClient.subscribe('/topic/newMovieFound', function (status) {
|
||||
const obj = JSON.parse(status.body);
|
||||
showSearchStatus(obj);
|
||||
shouldDisconnect(obj)
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -165,28 +165,15 @@ function disconnect() {
|
||||
console.log("Disconnected");
|
||||
}
|
||||
|
||||
function shouldDisconnect(obj) {
|
||||
if (obj && obj.searchedMovieCount && obj.totalMovieCount && obj.totalMovieCount === obj.searchedMovieCount) {
|
||||
disconnect();
|
||||
|
||||
//Cancel Search
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url: "cancelSearch",
|
||||
contentType: "application/json",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showSearchStatus(obj) {
|
||||
if (!obj) {
|
||||
searchResults.html("");
|
||||
} else {
|
||||
movieCounter++;
|
||||
let percentage = Math.trunc(obj.searchedMovieCount / obj.totalMovieCount * 100);
|
||||
searchPosition.html(`<h5>${obj.searchedMovieCount} of ${obj.totalMovieCount} movies searched. ${percentage}% complete.</h5>`);
|
||||
|
||||
if(obj.nextMovie) {
|
||||
movieCounter++;
|
||||
searchResults.append(buildMovieDiv(obj.nextMovie));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
"use strict";let stompClient;let backButton;let copyToClipboard;let searchResults;let searchPosition;let progressContainer;let searchTitle;let searchDescription;let movieCounter;document.addEventListener("DOMContentLoaded",function(){const elements=document.querySelectorAll(".modal");M.Modal.init(elements);backButton=$("#cancel");copyToClipboard=$("#copyToClipboard");searchResults=$("#searchResults");searchPosition=$("#searchPosition");progressContainer=$("#progressContainer");searchTitle=$("#searchTitle");searchDescription=$("#searchDescription");backButton.click(function(){$("#warningModal").modal("open")});setCopyToClipboardEnabled(false);copyToClipboard.click(function(){CopyToClipboard("searchResults");M.toast({html:"Copied to Clipboard"})});$("#agree").click(function(){$.ajax({type:"PUT",url:"https://"+location.hostname+":"+location.port+"/cancelSearch",contentType:"application/json"});location.assign("index.html")});connect();search()});window.onbeforeunload=function(){disconnect()};function setCopyToClipboardEnabled(bool){if(bool){copyToClipboard.removeClass("disabled")}else{copyToClipboard.addClass("disabled")}}function search(){movieCounter=0;progressContainer.hide();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 libraries=JSON.parse(Cookies.get("libraries"));const address=Cookies.get("address");const port=Cookies.get("port");const plexToken=Cookies.get("plex_token");const movieDbApiKey=Cookies.get("movie_db_api_key");let plexMovieUrls=[];for(const library of libraries){let data={"X-Plex-Token":plexToken};let plexMovieUrl="http://"+address+":"+port+"/library/sections/"+library.key+"/all/?"+encodeQueryData(data);plexMovieUrls.push(plexMovieUrl)}const gaps={movieDbApiKey:movieDbApiKey,writeToFile:true,searchFromPlex:true,movieUrls:plexMovieUrls};$.ajax({type:"POST",url:"https://"+location.hostname+":"+location.port+"/submit",data:JSON.stringify(gaps),contentType:"application/json",timeout:0,success:function(movies){searchResults.html(buildMoviesDiv(movies));movieCounter=movies.length;searchTitle.text(`${movieCounter} movies to add to complete your collections`);searchDescription.text("Below is everything Gaps found that is missing from your movie collections.");progressContainer.hide();backButton.text("restart");setCopyToClipboardEnabled(true)},error:function(err){disconnect();let message="Unknown error. Check docker Gaps log file.";if(err){message=JSON.parse(err.responseText).message;console.error(message)}searchTitle.text("An error occurred...");searchDescription.text("");progressContainer.hide();backButton.text("restart");setCopyToClipboardEnabled(false)}});showSearchStatus()}function buildMoviesDiv(movies){let result="";for(let movie of movies){result+=buildMovieDiv(movie)}return result}function buildMovieDiv(movie){return"<div>"+buildMovie(movie)+"</div>"}function buildMovie(movie){return`${movie.name} (${movie.year}) from '${movie.collection}'`}function connect(){const socket=new SockJS("/gs-guide-websocket");stompClient=Stomp.over(socket);stompClient.connect({},function(){stompClient.subscribe("/topic/currentSearchResults",function(status){let obj=JSON.parse(status.body);showSearchStatus(obj);shouldDisconnect(obj)})})}function disconnect(){if(stompClient!==null){stompClient.disconnect()}console.log("Disconnected")}function shouldDisconnect(obj){if(obj&&obj.searchedMovieCount&&obj.totalMovieCount&&obj.totalMovieCount===obj.searchedMovieCount){disconnect();$.ajax({type:"PUT",url:"http://"+location.hostname+":"+location.port+"/cancelSearch",contentType:"application/json"})}}function showSearchStatus(obj){if(!obj||!obj.searchedMovieCount&&!obj.totalMovieCount&&obj.totalMovieCount===0){searchResults.html("")}else{progressContainer.show();let percentage=Math.trunc(obj.searchedMovieCount/obj.totalMovieCount*100);searchPosition.html(`<h5>${obj.searchedMovieCount} of ${obj.totalMovieCount} movies searched. ${percentage}% complete.</h5>`);movieCounter=obj.moviesFound.length;searchResults.html(buildMoviesDiv(obj.moviesFound));$("#progressBar").css("width",percentage+"%")}}function encodeQueryData(data){const ret=[];for(let d in data){ret.push(encodeURIComponent(d)+"="+encodeURIComponent(data[d]))}return ret.join("&")}function CopyToClipboard(containerId){let range;if(document.selection){range=document.body.createTextRange();range.moveToElementText(document.getElementById(containerId));range.select().createTextRange();document.execCommand("copy")}else if(window.getSelection){range=document.createRange();range.selectNode(document.getElementById(containerId));window.getSelection().addRange(range);document.execCommand("copy")}}
|
||||
"use strict";let stompClient;let backButton;let copyToClipboard;let searchResults;let searchPosition;let progressContainer;let searchTitle;let searchDescription;let movieCounter;document.addEventListener("DOMContentLoaded",function(){const elements=document.querySelectorAll(".modal");M.Modal.init(elements);backButton=$("#cancel");copyToClipboard=$("#copyToClipboard");searchResults=$("#searchResults");searchPosition=$("#searchPosition");progressContainer=$("#progressContainer");searchTitle=$("#searchTitle");searchDescription=$("#searchDescription");backButton.click(function(){$("#warningModal").modal("open")});setCopyToClipboardEnabled(false);copyToClipboard.click(function(){CopyToClipboard("searchResults");M.toast({html:"Copied to Clipboard"})});$("#agree").click(function(){$.ajax({type:"PUT",url:"cancelSearch",contentType:"application/json"});location.assign("index.html")});connect();search()});window.onbeforeunload=function(){disconnect()};function setCopyToClipboardEnabled(bool){if(bool){copyToClipboard.removeClass("disabled")}else{copyToClipboard.addClass("disabled")}}function search(){movieCounter=0;progressContainer.show();searchResults.html("");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 libraries=JSON.parse(Cookies.get("libraries"));const address=Cookies.get("address");const port=Cookies.get("port");const plexToken=Cookies.get("plex_token");const movieDbApiKey=Cookies.get("movie_db_api_key");let plexMovieUrls=[];for(const library of libraries){let data={"X-Plex-Token":plexToken};let plexMovieUrl="http://"+address+":"+port+"/library/sections/"+library.key+"/all/?"+encodeQueryData(data);plexMovieUrls.push(plexMovieUrl)}const gaps={movieDbApiKey:movieDbApiKey,writeToFile:true,searchFromPlex:true,movieUrls:plexMovieUrls};$.ajax({type:"POST",url:"submit",data:JSON.stringify(gaps),contentType:"application/json",timeout:0,success:function(){searchTitle.text(`${movieCounter} movies to add to complete your collections`);searchDescription.text("Below is everything Gaps found that is missing from your movie collections.");progressContainer.hide();searchPosition.html("");backButton.text("restart");setCopyToClipboardEnabled(true);disconnect()},error:function(err){disconnect();let message="Unknown error. Check docker Gaps log file.";if(err){message=JSON.parse(err.responseText).message;console.error(message)}searchTitle.text("An error occurred...");searchDescription.text("");searchPosition.html("");progressContainer.hide();backButton.text("restart");setCopyToClipboardEnabled(false)}});showSearchStatus()}function buildMovieDiv(movie){return"<div>"+buildMovie(movie)+"</div>"}function buildMovie(movie){return`${movie.name} (${movie.year}) from '${movie.collection}'`}function connect(){const socket=new SockJS("/gs-guide-websocket");stompClient=Stomp.over(socket);stompClient.connect({},function(){stompClient.subscribe("/topic/newMovieFound",function(status){const obj=JSON.parse(status.body);showSearchStatus(obj)})})}function disconnect(){if(stompClient!==null){stompClient.disconnect()}console.log("Disconnected")}function showSearchStatus(obj){if(!obj){searchResults.html("")}else{let percentage=Math.trunc(obj.searchedMovieCount/obj.totalMovieCount*100);searchPosition.html(`<h5>${obj.searchedMovieCount} of ${obj.totalMovieCount} movies searched. ${percentage}% complete.</h5>`);if(obj.nextMovie){movieCounter++;searchResults.append(buildMovieDiv(obj.nextMovie))}}}function encodeQueryData(data){const ret=[];for(let d in data){ret.push(encodeURIComponent(d)+"="+encodeURIComponent(data[d]))}return ret.join("&")}function CopyToClipboard(containerId){let range;if(document.selection){range=document.body.createTextRange();range.moveToElementText(document.getElementById(containerId));range.select().createTextRange();document.execCommand("copy")}else if(window.getSelection){range=document.createRange();range.selectNode(document.getElementById(containerId));window.getSelection().addRange(range);document.execCommand("copy")}}
|
||||
@@ -8,16 +8,15 @@
|
||||
* 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;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import com.jasonhhouse.gaps.service.GapsSearchService;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@@ -28,17 +27,17 @@ import java.util.concurrent.Future;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class GapsSearchBeanTest {
|
||||
class GapsSearchServiceTest {
|
||||
|
||||
private final Gaps gaps = new Gaps();
|
||||
private GapsUrlGeneratorTest gapsUrlGeneratorTest;
|
||||
private GapsSearchBean gapsSearch;
|
||||
private GapsSearchService gapsSearch;
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
gapsUrlGeneratorTest = new GapsUrlGeneratorTest();
|
||||
SimpMessagingTemplate template = new SimpMessagingTemplate((message, l) -> true);
|
||||
gapsSearch = new GapsSearchBean(gapsUrlGeneratorTest, template);
|
||||
gapsSearch = new GapsSearchService(gapsUrlGeneratorTest, template);
|
||||
|
||||
// Create a MockWebServer. These are lean enough that you can create a new
|
||||
// instance for every unit test.
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jasonhhouse.Gaps;
|
||||
package com.jasonhhouse.gaps;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.mockwebserver.Dispatcher;
|
||||
Reference in New Issue
Block a user