Adding schedule support through web UI

This commit is contained in:
Jason House
2020-08-05 13:14:37 +09:00
parent 7d0664e3ec
commit d8ea2866c5
9 changed files with 96 additions and 12 deletions

View File

@@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Schedule {
HOURLY("Hourly", "0 57 * * * *", 0),
HOURLY("Hourly", "0 48 * * * *", 0),
DAILY_4AM("Daily", "0 0 4 * * ?", 1),
EVERY_MONDAY("Weekly", "0 0 4 ? * MON *", 2),
EVERY_TWO_WEEKS("Bi-weekly", "0 0 4 1,15 * ? *", 3),

View File

@@ -9,6 +9,7 @@
*/
package com.jasonhhouse.gaps.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jasonhhouse.gaps.GapsService;
@@ -17,6 +18,7 @@ import com.jasonhhouse.gaps.PlexSearch;
import com.jasonhhouse.gaps.PlexServer;
import com.jasonhhouse.gaps.service.IoService;
import com.jasonhhouse.gaps.service.PlexQueryImpl;
import com.jasonhhouse.gaps.service.SchedulerService;
import com.jasonhhouse.gaps.service.TmdbService;
import java.io.IOException;
import java.util.List;
@@ -56,13 +58,15 @@ public class ConfigurationController {
private final PlexQueryImpl plexQuery;
private final GapsService gapsService;
private final IoService ioService;
private final SchedulerService schedulerService;
public ConfigurationController(TmdbService tmdbService, SimpMessagingTemplate template, PlexQueryImpl plexQuery, GapsService gapsService, IoService ioService) {
public ConfigurationController(TmdbService tmdbService, SimpMessagingTemplate template, PlexQueryImpl plexQuery, GapsService gapsService, IoService ioService, SchedulerService schedulerService) {
this.tmdbService = tmdbService;
this.template = template;
this.plexQuery = plexQuery;
this.gapsService = gapsService;
this.ioService = ioService;
this.schedulerService = schedulerService;
}
@GetMapping(produces = MediaType.TEXT_HTML_VALUE)
@@ -81,6 +85,11 @@ public class ConfigurationController {
ModelAndView modelAndView = new ModelAndView("configuration");
modelAndView.addObject("plexSearch", gapsService.getPlexSearch());
try {
modelAndView.addObject("schedules", schedulerService.getAllSchedules());
} catch (JsonProcessingException e) {
LOGGER.error("Could not parse schedules into JSON", e);
}
return modelAndView;
}

View File

@@ -11,8 +11,10 @@
package com.jasonhhouse.gaps.controller;
import com.jasonhhouse.gaps.Payload;
import com.jasonhhouse.gaps.Schedule;
import com.jasonhhouse.gaps.service.SchedulerService;
import java.io.IOException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -68,7 +70,7 @@ public class SchedulerController {
@GetMapping(value = "/all",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getAllSchedules() {
public ResponseEntity<?> getAllSchedules() {
LOGGER.info("getAllSchedules()");
try {
return ResponseEntity.ok().body(schedulerService.getAllSchedules());

View File

@@ -65,10 +65,9 @@ public class SchedulerService {
return ioService.readProperties().getSchedule();
}
public String getAllSchedules() throws JsonProcessingException {
public List<Schedule> getAllSchedules() throws JsonProcessingException {
LOGGER.info("getAllSchedules()");
List<Schedule> schedules = Schedule.getAllSchedules();
return objectMapper.writeValueAsString(schedules);
return Schedule.getAllSchedules();
}
public String getJsonSchedule() throws IOException {

View File

@@ -13,6 +13,7 @@ import {Payload} from '/js/modules/payload.min.js';
let plexSpinner, plexSaveSuccess, plexSaveError, plexTestSuccess, plexTestError, plexDeleteSuccess, plexDeleteError,
plexDuplicateError;
let tmdbSpinner, tmdbSaveSuccess, tmdbSaveError, tmdbTestSuccess, tmdbTestError;
let scheduleSpinner, scheduleSaveSuccess, scheduleSaveError;
let deleteAllError, deleteAllSuccess;
window.addEventListener('load', function () {
@@ -45,6 +46,9 @@ document.addEventListener('DOMContentLoaded', function () {
tmdbTestSuccess = $('#tmdbTestSuccess');
tmdbTestError = $('#tmdbTestError');
plexDuplicateError = $('#plexDuplicateError');
scheduleSpinner = $('#scheduleSpinner');
scheduleSaveSuccess = $('#scheduleSaveSuccess');
scheduleSaveError = $('#scheduleSaveError');
deleteAllError = $('#deleteAllError');
deleteAllSuccess = $('#deleteAllSuccess');
@@ -88,6 +92,7 @@ document.addEventListener('DOMContentLoaded', function () {
window.addPlexServer = addPlexServer;
window.testExistingPlexServer = testExistingPlexServer;
window.removePlexServer = removePlexServer;
window.saveSchedule = saveSchedule;
window.setDeleteAllEnabledOrDisabled = setDeleteAllEnabledOrDisabled;
window.nuke = nuke;
});
@@ -249,6 +254,29 @@ function removePlexServer(machineIdentifier) {
});
}
function saveSchedule() {
hideAllAlertsAndSpinners();
const id = $('#setSchedule').val();
$.ajax({
type: "PUT",
url: `/schedule/${id}`,
success: function (result) {
hideAllAlertsAndSpinners();
if (result && result.code === Payload.SCHEDULE_UPDATED) {
scheduleSaveSuccess.show();
} else {
scheduleSaveError.show();
}
},
error: function () {
hideAllAlertsAndSpinners();
scheduleSaveError.show();
}
});
}
function setDeleteAllEnabledOrDisabled() {
$('#deleteAll').prop("disabled", !$('#confirmDeleteAll').is(":checked"));
}

File diff suppressed because one or more lines are too long

View File

@@ -29,5 +29,9 @@ export const Payload = Object.freeze({
'PLEX_LIBRARY_MOVIE_FOUND': 40,
'PLEX_LIBRARY_MOVIE_NOT_FOUND': 41,
'RECOMMENDED_MOVIES_FOUND': 50,
'RECOMMENDED_MOVIES_NOT_FOUND': 51
'RECOMMENDED_MOVIES_NOT_FOUND': 51,
'SCHEDULE_FOUND': 60,
'SCHEDULE_NOT_FOUND': 61,
'SCHEDULE_UPDATED': 62,
'SCHEDULE_NOT_UPDATED': 63
});

View File

@@ -1 +1 @@
export const Payload=Object.freeze({UNKNOWN_ERROR:-1,SEARCH_SUCCESSFUL:0,SEARCH_CANCELLED:1,SEARCH_FAILED:2,OWNED_MOVIES_CANNOT_BE_EMPTY:3,PLEX_CONNECTION_SUCCEEDED:10,PLEX_CONNECTION_FAILED:11,PARSING_PLEX_FAILED:12,PLEX_URL_ERROR:13,PLEX_LIBRARIES_FOUND:13,DUPLICATE_PLEX_LIBRARY:14,TMDB_KEY_VALID:20,TMDB_KEY_INVALID:21,TMDB_CONNECTION_ERROR:22,TMDB_KEY_SAVE_SUCCESSFUL:23,TMDB_KEY_SAVE_UNSUCCESSFUL:24,NUKE_SUCCESSFUL:30,NUKE_UNSUCCESSFUL:31,PLEX_LIBRARY_MOVIE_FOUND:40,PLEX_LIBRARY_MOVIE_NOT_FOUND:41,RECOMMENDED_MOVIES_FOUND:50,RECOMMENDED_MOVIES_NOT_FOUND:51});
export const Payload=Object.freeze({UNKNOWN_ERROR:-1,SEARCH_SUCCESSFUL:0,SEARCH_CANCELLED:1,SEARCH_FAILED:2,OWNED_MOVIES_CANNOT_BE_EMPTY:3,PLEX_CONNECTION_SUCCEEDED:10,PLEX_CONNECTION_FAILED:11,PARSING_PLEX_FAILED:12,PLEX_URL_ERROR:13,PLEX_LIBRARIES_FOUND:13,DUPLICATE_PLEX_LIBRARY:14,TMDB_KEY_VALID:20,TMDB_KEY_INVALID:21,TMDB_CONNECTION_ERROR:22,TMDB_KEY_SAVE_SUCCESSFUL:23,TMDB_KEY_SAVE_UNSUCCESSFUL:24,NUKE_SUCCESSFUL:30,NUKE_UNSUCCESSFUL:31,PLEX_LIBRARY_MOVIE_FOUND:40,PLEX_LIBRARY_MOVIE_NOT_FOUND:41,RECOMMENDED_MOVIES_FOUND:50,RECOMMENDED_MOVIES_NOT_FOUND:51,SCHEDULE_FOUND:60,SCHEDULE_NOT_FOUND:61,SCHEDULE_UPDATED:62,SCHEDULE_NOT_UPDATED:63});

View File

@@ -83,6 +83,9 @@
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#plex" id="plexTab">Plex</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#schedule" id="scheduleTab">Schedule</a>
</li>
<li class="nav-item" hidden>
<a class="nav-link disabled" data-ol-has-click-handler="" href="#folders" id="folderTab">Folders</a>
</li>
@@ -267,6 +270,42 @@
</div>
</div>
</div>
<div class="tab-pane fade top-margin" id="schedule">
<p>Gaps can be set to automatically run. This is through a cron job that will search for new Plex Libraries
on each configured server, then search for all movies in each library, and produce a missing movie
list.</p>
<form class="needs-validation" id="scheduleConfiguration" novalidate th:object="${plexSearch}">
<div class="form-group">
<label for="setSchedule">Set Schedule</label>
<select class="form-control" id="setSchedule">
<div th:each="schedule : ${schedules}" th:remove="tag">
<option th:value="${schedule.id}" th:text="${schedule.message}"></option>
</div>
</select>
</div>
<a class="btn btn-primary" href="javascript:void(0)" id="saveSchedule" onclick="saveSchedule();"
type="button">Save</a>
</form>
<div class="spinner-border text-primary gaps-hide top-margin" id="scheduleSpinner" role="status">
<span class="sr-only">Loading...</span>
</div>
<div class="alert alert-dismissible alert-danger gaps-hide top-margin" id="scheduleSaveError">
<button class="close" data-hide="alert" type="button">&times;</button>
<h4 class="alert-heading">Error!</h4>
<p class="mb-0">Could not save your schedule. Check the logs and try again.</p>
</div>
<div class="alert alert-dismissible alert-success gaps-hide top-margin" id="scheduleSaveSuccess">
<button class="close" data-hide="alert" type="button">&times;</button>
<h4 class="alert-heading">Success!</h4>
<p class="mb-0">Your schedule saved successfully.</p>
</div>
</div>
<div class="tab-pane fade top-margin" id="folders">
<p>folders</p>
</div>
@@ -297,7 +336,8 @@
Please enter a valid time.
</div>
</div>
<small class="form-text text-muted" id="plexReadTimeoutHelp">Default read timeout (in milliseconds).</small>
<small class="form-text text-muted" id="plexReadTimeoutHelp">Default read timeout (in
milliseconds).</small>
</div>
<div class="form-group">
<label for="port">Plex Write Timeout</label>
@@ -309,7 +349,8 @@
Please enter a valid time.
</div>
</div>
<small class="form-text text-muted" id="plexWriteTimeoutHelp">Default write timeout (in milliseconds).</small>
<small class="form-text text-muted" id="plexWriteTimeoutHelp">Default write timeout (in
milliseconds).</small>
</div>
<a class="btn btn-primary" href="javascript:void(0)" id="updateNetwork" onclick="updateNetwork();"
@@ -322,7 +363,8 @@
<form class="needs-validation" id="advancedConfiguration" novalidate>
<div class="form-group">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="confirmDeleteAll" onchange="setDeleteAllEnabledOrDisabled();">
<input type="checkbox" class="form-check-input" id="confirmDeleteAll"
onchange="setDeleteAllEnabledOrDisabled();">
<label class="form-check-label" for="confirmDeleteAll">Delete All Stored Data</label>
</div>
</div>