diff --git a/core/src/main/java/net/brlns/gdownloader/downloader/AbstractDownloader.java b/core/src/main/java/net/brlns/gdownloader/downloader/AbstractDownloader.java index 3c90425..6920db9 100644 --- a/core/src/main/java/net/brlns/gdownloader/downloader/AbstractDownloader.java +++ b/core/src/main/java/net/brlns/gdownloader/downloader/AbstractDownloader.java @@ -41,6 +41,8 @@ public AbstractDownloader(DownloadManager managerIn) { manager = managerIn; } + public abstract boolean isEnabled(); + protected abstract boolean canConsumeUrl(String inputUrl); protected abstract boolean tryQueryVideo(QueueEntry queueEntry); diff --git a/core/src/main/java/net/brlns/gdownloader/downloader/DirectHttpDownloader.java b/core/src/main/java/net/brlns/gdownloader/downloader/DirectHttpDownloader.java index f18336f..a2b3a7e 100644 --- a/core/src/main/java/net/brlns/gdownloader/downloader/DirectHttpDownloader.java +++ b/core/src/main/java/net/brlns/gdownloader/downloader/DirectHttpDownloader.java @@ -86,6 +86,11 @@ public DirectHttpDownloader(DownloadManager managerIn) { super(managerIn); } + @Override + public boolean isEnabled() { + return main.getConfig().isDirectHttpEnabled(); + } + @Override public DownloaderIdEnum getDownloaderId() { return DownloaderIdEnum.DIRECT_HTTP; @@ -98,7 +103,7 @@ public boolean isMainDownloader() { @Override protected boolean canConsumeUrl(String inputUrl) { - return main.getConfig().isDirectHttpEnabled() + return isEnabled() && !(inputUrl.contains("ytimg") || inputUrl.contains("ggpht") || inputUrl.endsWith("youtube.com/")); @@ -153,12 +158,13 @@ protected DownloadResult tryDownload(QueueEntry entry) throws Exception { }); lastOutput = PREFIX + "Download complete"; - - entry.getDownloadStarted().set(false); + entry.updateStatus(DownloadStatusEnum.DOWNLOADING, lastOutput); } catch (Exception e) { lastOutput = PREFIX + e.getMessage(); success = false; + } finally { + entry.getDownloadStarted().set(false); } log.info(lastOutput); @@ -381,7 +387,7 @@ private boolean downloadFile(QueueEntry queueEntry, ProgressUpdater progressCall future.get(); } } catch (Exception e) { - throw new IOException("Failed to download a chunk: " + fileUrl, e); + throw new IOException("Failed to download a chunk: " + fileUrl + ": " + e.getMessage(), e); } if (downloadedBytes.get() != totalBytes) { @@ -485,7 +491,7 @@ private boolean downloadChunk(ChunkData chunkData) throws IOException { if (attempt == MAX_CHUNK_RETRIES) { chunkData.getAbortHook().set(true); - throw new IOException("Failed to download file after " + MAX_CHUNK_RETRIES + " attempts."); + throw new IOException("Failed to download file after " + MAX_CHUNK_RETRIES + " attempts: " + e.getMessage(), e); } } finally { if (connection != null) { diff --git a/core/src/main/java/net/brlns/gdownloader/downloader/DownloadManager.java b/core/src/main/java/net/brlns/gdownloader/downloader/DownloadManager.java index 2564e26..1167e5f 100644 --- a/core/src/main/java/net/brlns/gdownloader/downloader/DownloadManager.java +++ b/core/src/main/java/net/brlns/gdownloader/downloader/DownloadManager.java @@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; import lombok.AccessLevel; @@ -73,7 +74,6 @@ public class DownloadManager { private final List> listeners = new ArrayList<>(); private final List downloaders = new ArrayList<>(); - private final Set capturedLinks = Collections.synchronizedSet(new HashSet<>()); private final Set capturedPlaylists = Collections.synchronizedSet(new HashSet<>()); @@ -93,6 +93,8 @@ public class DownloadManager { private final AtomicBoolean downloadsRunning = new AtomicBoolean(false); private final AtomicBoolean downloadsManuallyStarted = new AtomicBoolean(false); + private final AtomicReference suggestedDownloaderId = new AtomicReference<>(null); + private final ExpiringSet urlIgnoreSet = new ExpiringSet<>(TimeUnit.SECONDS, 5); private final ExecutorService forcefulExecutor = Executors.newCachedThreadPool();// No limits, power to ya @@ -135,14 +137,8 @@ public DownloadManager(GDownloader mainIn) { }); downloaders.add(new YtDlpDownloader(this)); - - if (main.getConfig().isGalleryDlEnabled()) { - downloaders.add(new GalleryDlDownloader(this)); - } - - if (main.getConfig().isDebugMode()) { - downloaders.add(new DirectHttpDownloader(this)); - } + downloaders.add(new GalleryDlDownloader(this)); + downloaders.add(new DirectHttpDownloader(this)); } public boolean isBlocked() { @@ -187,6 +183,12 @@ private List getCompatibleDownloaders(String inputUrl) { .collect(Collectors.toUnmodifiableList()); } + public List getEnabledDownloaders() { + return downloaders.stream() + .filter(downloader -> downloader.isEnabled()) + .collect(Collectors.toUnmodifiableList()); + } + public CompletableFuture captureUrl(@Nullable String inputUrl, boolean force) { return captureUrl(inputUrl, force, main.getConfig().getPlaylistDownloadOption()); } @@ -395,7 +397,7 @@ public CompletableFuture captureUrl(@Nullable String inputUrl, boolean enqueueLast(queueEntry); if (main.getConfig().isAutoDownloadStart() && !downloadsRunning.get()) { - startDownloads(); + startDownloads(suggestedDownloaderId.get()); } future.complete(true); @@ -441,9 +443,15 @@ public void toggleDownloads() { } public void startDownloads() { + startDownloads(null); + } + + public void startDownloads(@Nullable DownloaderIdEnum downloaderId) { if (!downloadsBlocked.get()) { downloadsRunning.set(true); downloadsManuallyStarted.set(true); + suggestedDownloaderId.set(downloaderId); + fireListeners(); } } @@ -451,6 +459,8 @@ public void startDownloads() { public void stopDownloads() { downloadsRunning.set(false); downloadsManuallyStarted.set(false); + suggestedDownloaderId.set(null); + fireListeners(); } @@ -482,7 +492,7 @@ public void retryFailedDownloads() { restartDownload(entry, false); } - startDownloads(); + startDownloads(suggestedDownloaderId.get()); fireListeners(); } @@ -699,6 +709,9 @@ private void submitDownloadTask(QueueEntry entry, boolean force) { inProgressDownloads.offer(entry); DownloaderIdEnum forcedDownloader = entry.getForcedDownloader(); + if (forcedDownloader == null) { + forcedDownloader = suggestedDownloaderId.get(); + } int maxRetries = !main.getConfig().isAutoDownloadRetry() ? 1 : MAX_DOWNLOAD_RETRIES; String lastOutput = ""; @@ -743,11 +756,13 @@ private void submitDownloadTask(QueueEntry entry, boolean force) { entry.logError(lastOutput); if (disabled || unsupported || entry.getRetryCounter().get() >= maxRetries) { + entry.updateStatus(DownloadStatusEnum.FAILED, lastOutput); log.error("Download of {} failed on {}: {} supported downloader: {}", entry.getUrl(), downloaderId, lastOutput, !unsupported); entry.blackListDownloader(downloaderId); } else { + entry.updateStatus(DownloadStatusEnum.RETRYING, lastOutput); log.warn("Download of {} failed with {}, retrying ({}/{}): {}", entry.getUrl(), downloaderId, @@ -885,7 +900,7 @@ private void tryStopProcess(Process process) throws InterruptedException { public void close() { stopDownloads(); - clearQueue(RUNNING, true); + clearQueue(RUNNING, false); clearQueue(); for (AbstractDownloader downloader : downloaders) { diff --git a/core/src/main/java/net/brlns/gdownloader/downloader/GalleryDlDownloader.java b/core/src/main/java/net/brlns/gdownloader/downloader/GalleryDlDownloader.java index 1c4816c..b190cf0 100644 --- a/core/src/main/java/net/brlns/gdownloader/downloader/GalleryDlDownloader.java +++ b/core/src/main/java/net/brlns/gdownloader/downloader/GalleryDlDownloader.java @@ -65,6 +65,12 @@ public GalleryDlDownloader(DownloadManager managerIn) { super(managerIn); } + @Override + public boolean isEnabled() { + return getExecutablePath().isPresent() + && main.getConfig().isGalleryDlEnabled(); + } + @Override public DownloaderIdEnum getDownloaderId() { return DownloaderIdEnum.GALLERY_DL; @@ -77,8 +83,7 @@ public boolean isMainDownloader() { @Override protected boolean canConsumeUrl(String inputUrl) { - return getExecutablePath().isPresent() - && main.getConfig().isGalleryDlEnabled() + return isEnabled() && !(inputUrl.contains("ytimg") || inputUrl.contains("ggpht") || inputUrl.endsWith("youtube.com/")); @@ -256,7 +261,7 @@ private Pair processDownload(QueueEntry entry, List arg String line; while (manager.isRunning() && !entry.getCancelHook().get() && process.isAlive()) { if (Thread.currentThread().isInterrupted()) { - process.destroy(); + process.destroyForcibly(); throw new InterruptedException("Download interrupted"); } @@ -271,13 +276,11 @@ private Pair processDownload(QueueEntry entry, List arg Thread.sleep(100); } catch (InterruptedException e) { log.debug("Sleep interrupted, closing process"); - process.destroy(); + process.destroyForcibly(); } } } - entry.getDownloadStarted().set(false); - long stopped = System.currentTimeMillis() - start; if (!manager.isRunning() || entry.getCancelHook().get()) { @@ -299,6 +302,8 @@ private Pair processDownload(QueueEntry entry, List arg return null; } finally { + entry.getDownloadStarted().set(false); + // Our ProcessMonitor will take care of closing the underlying process. } } diff --git a/core/src/main/java/net/brlns/gdownloader/downloader/YtDlpDownloader.java b/core/src/main/java/net/brlns/gdownloader/downloader/YtDlpDownloader.java index dfdff7f..d9a6cd0 100644 --- a/core/src/main/java/net/brlns/gdownloader/downloader/YtDlpDownloader.java +++ b/core/src/main/java/net/brlns/gdownloader/downloader/YtDlpDownloader.java @@ -69,6 +69,11 @@ public YtDlpDownloader(DownloadManager managerIn) { super(managerIn); } + @Override + public boolean isEnabled() { + return getExecutablePath().isPresent();// TODO: allow disabling? + } + @Override public DownloaderIdEnum getDownloaderId() { return DownloaderIdEnum.YT_DLP; @@ -81,7 +86,7 @@ public boolean isMainDownloader() { @Override protected boolean canConsumeUrl(String inputUrl) { - return getExecutablePath().isPresent() + return isEnabled() && !(inputUrl.contains("ytimg") || inputUrl.contains("ggpht") || inputUrl.endsWith("youtube.com/") @@ -344,7 +349,7 @@ private Pair processDownload(QueueEntry entry, List arg while (manager.isRunning() && !entry.getCancelHook().get() && process.isAlive()) { if (Thread.currentThread().isInterrupted()) { log.debug("Process is closing"); - process.destroy(); + process.destroyForcibly(); throw new InterruptedException("Download interrupted"); } @@ -372,12 +377,10 @@ private Pair processDownload(QueueEntry entry, List arg Thread.sleep(100); } catch (InterruptedException e) { log.debug("Sleep interrupted, closing process"); - process.destroy(); + process.destroyForcibly(); } } - entry.getDownloadStarted().set(false); - long stopped = System.currentTimeMillis() - start; if (!manager.isRunning() || entry.getCancelHook().get()) { @@ -399,6 +402,8 @@ private Pair processDownload(QueueEntry entry, List arg return null; } finally { + entry.getDownloadStarted().set(false); + // Our ProcessMonitor will take care of closing the underlying process. } } diff --git a/core/src/main/java/net/brlns/gdownloader/ui/GUIManager.java b/core/src/main/java/net/brlns/gdownloader/ui/GUIManager.java index 10a7e92..106a6f4 100644 --- a/core/src/main/java/net/brlns/gdownloader/ui/GUIManager.java +++ b/core/src/main/java/net/brlns/gdownloader/ui/GUIManager.java @@ -43,7 +43,9 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.brlns.gdownloader.GDownloader; +import net.brlns.gdownloader.downloader.AbstractDownloader; import net.brlns.gdownloader.downloader.DownloadManager; +import net.brlns.gdownloader.downloader.enums.DownloaderIdEnum; import net.brlns.gdownloader.downloader.enums.QueueCategoryEnum; import net.brlns.gdownloader.ui.custom.*; import net.brlns.gdownloader.ui.dnd.WindowDragSourceListener; @@ -417,57 +419,85 @@ private JPanel createToolbar() { } )); - buttonPanel.add(createToggleDownloadsButton( - (state) -> { - if (state) { - return loadIcon("/assets/pause.png", ICON); - } else { - if (main.getDownloadManager().getQueuedDownloads() > 0) { - return loadIcon("/assets/play.png", QUEUE_ACTIVE_ICON); + { + JButton toogledDownloadsButton = createToggleDownloadsButton( + (state) -> { + if (state) { + return loadIcon("/assets/pause.png", ICON); } else { - return loadIcon("/assets/play.png", ICON); + if (main.getDownloadManager().getQueuedDownloads() > 0) { + return loadIcon("/assets/play.png", QUEUE_ACTIVE_ICON); + } else { + return loadIcon("/assets/play.png", ICON); + } } + }, + (state) -> state + ? loadIcon("/assets/pause.png", ICON_HOVER) + : loadIcon("/assets/play.png", ICON_HOVER), + (state) -> state + ? "gui.stop_downloads.tooltip" + : "gui.start_downloads.tooltip", + main.getDownloadManager()::isRunning, + () -> { + main.getDownloadManager().toggleDownloads(); } - }, - (state) -> state - ? loadIcon("/assets/pause.png", ICON_HOVER) - : loadIcon("/assets/play.png", ICON_HOVER), - (state) -> state - ? "gui.stop_downloads.tooltip" - : "gui.start_downloads.tooltip", - main.getDownloadManager()::isRunning, - () -> { - main.getDownloadManager().toggleDownloads(); - } - )); + ); - JButton clearQueueButton = createButton( - loadIcon("/assets/erase.png", ICON), - loadIcon("/assets/erase.png", ICON_HOVER), - "gui.clear_download_queue.tooltip", - e -> main.getDownloadManager().clearQueue() - ); + toogledDownloadsButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + Map rightClickMenu = new LinkedHashMap<>(); + + for (AbstractDownloader downloader : main.getDownloadManager().getEnabledDownloaders()) { + DownloaderIdEnum downloaderId = downloader.getDownloaderId(); + rightClickMenu.put( + l10n("gui.start_downloads.download_using", downloaderId.getDisplayName()), + new RunnableMenuEntry(() -> { + main.getDownloadManager().stopDownloads(); + main.getDownloadManager().startDownloads(downloaderId); + }) + ); + } - Map rightClickMenu = new LinkedHashMap<>(); - rightClickMenu.put(l10n("gui.clear_download_queue.clear_failed"), - new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.FAILED))); - rightClickMenu.put(l10n("gui.clear_download_queue.clear_completed"), - new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.COMPLETED))); - rightClickMenu.put(l10n("gui.clear_download_queue.clear_queued"), - new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.QUEUED))); - rightClickMenu.put(l10n("gui.clear_download_queue.clear_running"), - new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.RUNNING))); - - clearQueueButton.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (SwingUtilities.isRightMouseButton(e)) { - showRightClickMenu(clearQueueButton, rightClickMenu, e.getX(), e.getY()); + showRightClickMenu(toogledDownloadsButton, rightClickMenu, e.getX(), e.getY()); + } } - } - }); + }); + + buttonPanel.add(toogledDownloadsButton); + } - buttonPanel.add(clearQueueButton); + { + JButton clearQueueButton = createButton( + loadIcon("/assets/erase.png", ICON), + loadIcon("/assets/erase.png", ICON_HOVER), + "gui.clear_download_queue.tooltip", + e -> main.getDownloadManager().clearQueue() + ); + + Map rightClickMenu = new LinkedHashMap<>(); + rightClickMenu.put(l10n("gui.clear_download_queue.clear_failed"), + new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.FAILED))); + rightClickMenu.put(l10n("gui.clear_download_queue.clear_completed"), + new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.COMPLETED))); + rightClickMenu.put(l10n("gui.clear_download_queue.clear_queued"), + new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.QUEUED))); + rightClickMenu.put(l10n("gui.clear_download_queue.clear_running"), + new RunnableMenuEntry(() -> main.getDownloadManager().clearQueue(QueueCategoryEnum.RUNNING))); + + clearQueueButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + showRightClickMenu(clearQueueButton, rightClickMenu, e.getX(), e.getY()); + } + } + }); + + buttonPanel.add(clearQueueButton); + } buttonPanel.add(createButton( loadIcon("/assets/settings.png", ICON), diff --git a/core/src/main/java/net/brlns/gdownloader/ui/SettingsPanel.java b/core/src/main/java/net/brlns/gdownloader/ui/SettingsPanel.java index 24e7d94..52c8d4f 100644 --- a/core/src/main/java/net/brlns/gdownloader/ui/SettingsPanel.java +++ b/core/src/main/java/net/brlns/gdownloader/ui/SettingsPanel.java @@ -865,7 +865,7 @@ public void insertUpdate(DocumentEvent e) { "settings.downloader.direct_http.enabled", settings::isDirectHttpEnabled, settings::setDirectHttpEnabled, - true + false ); addSlider(panel, gbcPanel, diff --git a/core/src/main/resources/lang/language_en.properties b/core/src/main/resources/lang/language_en.properties index 34be77e..a6278d3 100644 --- a/core/src/main/resources/lang/language_en.properties +++ b/core/src/main/resources/lang/language_en.properties @@ -94,6 +94,7 @@ gui.restart_download=Restart Download gui.retry_failed_downloads.tooltip=Click to Retry Failed Downloads gui.start_clipboard_monitor.tooltip=Click to Start Monitoring the Clipboard For New Links gui.start_downloads.tooltip=Click to Start Downloads +gui.start_downloads.download_using=Start downloads using: {0} gui.statusbar.completed=Completed gui.statusbar.failed=Failed gui.statusbar.queued=Queued diff --git a/core/src/main/resources/lang/language_es_MX.properties b/core/src/main/resources/lang/language_es_MX.properties index f920f0a..21df414 100644 --- a/core/src/main/resources/lang/language_es_MX.properties +++ b/core/src/main/resources/lang/language_es_MX.properties @@ -94,6 +94,7 @@ gui.restart_download=Reiniciar Descarga gui.retry_failed_downloads.tooltip=Haz Clic para Reintentar Descargas Fallidas gui.start_clipboard_monitor.tooltip=Haz Clic para Monitorear el Portapapeles en Busca de Nuevos Enlaces gui.start_downloads.tooltip=Haz Clic para Iniciar Descargas +gui.start_downloads.download_using=Iniciar Descargas Usando: {0} gui.statusbar.completed=Completado gui.statusbar.failed=Fallido gui.statusbar.queued=En Cola diff --git a/core/src/main/resources/lang/language_pt_BR.properties b/core/src/main/resources/lang/language_pt_BR.properties index 1bd2d4f..e93ff47 100644 --- a/core/src/main/resources/lang/language_pt_BR.properties +++ b/core/src/main/resources/lang/language_pt_BR.properties @@ -94,6 +94,7 @@ gui.restart_download=Reiniciar Download gui.retry_failed_downloads.tooltip=Clique Para Repetir Downloads Falhados gui.start_clipboard_monitor.tooltip=Clique Para Monitorar a \u00c1rea de Transfer\u00eancia Por Novos Links gui.start_downloads.tooltip=Clique Para Iniciar Downloads +gui.start_downloads.download_using=Iniciar Downloads Usando: {0} gui.statusbar.completed=Conclu\u00eddo gui.statusbar.failed=Falhou gui.statusbar.queued=Na Fila