mirror of
https://github.com/JasonHHouse/gaps.git
synced 2026-02-05 01:59:35 -06:00
Adding schedule support through web UI
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
});
|
||||
@@ -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});
|
||||
@@ -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">×</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">×</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>
|
||||
|
||||
Reference in New Issue
Block a user