package ctbrec.ui.action; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.eclipse.jetty.io.RuntimeIOException; import ctbrec.GlobalThreadPool; import ctbrec.Model; import ctbrec.recorder.Recorder; import ctbrec.recorder.download.StreamSource; import ctbrec.sites.ModelOfflineException; import ctbrec.ui.StreamSourceSelectionDialog; import ctbrec.ui.controls.Dialogs; import javafx.application.Platform; import javafx.scene.Cursor; import javafx.scene.Node; import lombok.extern.slf4j.Slf4j; @Slf4j public class SwitchStreamResolutionAction { private Node source; private Model selectedModel; private Recorder recorder; public SwitchStreamResolutionAction(Node source, Model selectedModel, Recorder recorder) { this.source = source; this.selectedModel = selectedModel; this.recorder = recorder; } public CompletableFuture execute() { source.setCursor(Cursor.WAIT); var couldntSwitchHeaderText = "Couldn't switch stream resolution"; return CompletableFuture.supplyAsync(() -> { try { checkOnlineState(); return Boolean.TRUE; // model is online } catch (ModelOfflineException e) { return Boolean.FALSE; // model is offline } }, GlobalThreadPool.get()) .thenAccept(isOnline -> Platform.runLater(() -> { if (isOnline) { // --- model is online: open selection dialog --- StreamSourceSelectionDialog dialog = new StreamSourceSelectionDialog(source.getScene(), selectedModel); Optional selectedSource = dialog.showAndWait(); if (selectedSource.isPresent()) { StreamSource src = selectedSource.get(); if (src != StreamSourceSelectionDialog.LOADING) { int index = dialog.indexOf(src); selectedModel.setStreamUrlIndex(index); try { recorder.switchStreamSource(selectedModel); } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) { log.error(couldntSwitchHeaderText, e); Dialogs.showError(source.getScene(), couldntSwitchHeaderText, "Error while switching stream resolution", e); } } } } else { // --- model is offline: ask if user wants to reset --- boolean confirmed = Dialogs.showConfirmDialog( "Model is offline", "Yes to reset to Default (Best resolution),\nNo to leave existing resolution unchanged.", "", source.getScene() ); if (confirmed) { selectedModel.setStreamUrlIndex(-1); try { recorder.switchStreamSource(selectedModel); // persist the change } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) { log.error("Couldn't update recorder with reset stream index", e); Dialogs.showError(source.getScene(), "Couldn't reset stream resolution", "Error while updating stream resolution", e); } // show confirmation popup Dialogs.showError( source.getScene(), "Stream Resolution Reset", "Stream resolution has been reset to Best (default).", null ); } } source.setCursor(Cursor.DEFAULT); })) .exceptionally(ex -> { log.error("Unexpected error while switching resolution", ex); Platform.runLater(() -> { Dialogs.showError(source.getScene(), couldntSwitchHeaderText, "Unexpected error occurred", ex); source.setCursor(Cursor.DEFAULT); }); return null; }); } private void checkOnlineState() { try { if (!selectedModel.isOnline(true)) { throw new ModelOfflineException(selectedModel); } } catch (IOException | ExecutionException e) { throw new RuntimeIOException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); // NOSONAR } } }