├── settings.gradle ├── readme-img ├── batch.png ├── logs.png ├── main.png ├── details.png ├── single.png ├── batch-list.png ├── extension.gif ├── settings-1.png ├── settings-2.png ├── download-folder.png ├── queue-scheduler.png └── queue-settings.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── extensions ├── firefox │ ├── resources │ │ ├── icons │ │ │ └── logo.png │ │ ├── images │ │ │ └── popup.png │ │ ├── options.html │ │ ├── main.css │ │ └── overlay.css │ ├── _locales │ │ └── en │ │ │ └── messages.json │ ├── manifest.json │ └── scripts │ │ ├── content.js │ │ ├── options.js │ │ ├── uSelect_statemachine.js │ │ └── connector.js └── chrome_based │ ├── resources │ ├── icons │ │ └── logo.png │ ├── images │ │ └── popup.png │ ├── options.html │ ├── main.css │ └── overlay.css │ ├── _locales │ └── en │ │ └── messages.json │ ├── manifest.json │ └── scripts │ ├── content.js │ ├── options.js │ ├── uSelect_statemachine.js │ └── connector.js ├── src ├── main │ ├── resources │ │ ├── io │ │ │ └── beanvortex │ │ │ │ └── bitkip │ │ │ │ ├── icons │ │ │ │ ├── logo.icns │ │ │ │ ├── logo.ico │ │ │ │ ├── logo.png │ │ │ │ ├── drag-and-drop-dark.png │ │ │ │ └── drag-and-drop-light.png │ │ │ │ ├── css │ │ │ │ ├── queueSetting.css │ │ │ │ ├── settings.css │ │ │ │ ├── dark_mode.css │ │ │ │ ├── main.css │ │ │ │ ├── newDownload.css │ │ │ │ └── light_mode.css │ │ │ │ └── fxml │ │ │ │ ├── newDownload.fxml │ │ │ │ ├── logs.fxml │ │ │ │ ├── newQueue.fxml │ │ │ │ ├── refreshLink.fxml │ │ │ │ ├── changeCredentials.fxml │ │ │ │ ├── about.fxml │ │ │ │ ├── main.fxml │ │ │ │ ├── batchList.fxml │ │ │ │ ├── batchDownload.fxml │ │ │ │ ├── singleDownload.fxml │ │ │ │ └── details.fxml │ │ └── logback.xml │ └── java │ │ ├── io │ │ └── beanvortex │ │ │ └── bitkip │ │ │ ├── models │ │ │ ├── BatchURLModel.java │ │ │ ├── SingleURLModel.java │ │ │ ├── DownloadStatus.java │ │ │ ├── TurnOffMode.java │ │ │ ├── UpdateModel.java │ │ │ ├── StartedQueue.java │ │ │ ├── Credentials.java │ │ │ ├── FileType.java │ │ │ ├── LinkModel.java │ │ │ ├── ScheduleModel.java │ │ │ └── QueueModel.java │ │ │ ├── Launcher.java │ │ │ ├── exceptions │ │ │ ├── DeniedException.java │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── config │ │ │ ├── observers │ │ │ │ ├── QueueObserver.java │ │ │ │ ├── ThemeObserver.java │ │ │ │ ├── ThemeSubject.java │ │ │ │ └── QueueSubject.java │ │ │ └── AppConfigs.java │ │ │ ├── controllers │ │ │ ├── interfaces │ │ │ │ └── FXMLController.java │ │ │ ├── ChangeCredentialsController.java │ │ │ ├── AboutController.java │ │ │ ├── RefreshController.java │ │ │ ├── NewQueueController.java │ │ │ ├── LogsController.java │ │ │ └── NewDownloadController.java │ │ │ ├── api │ │ │ ├── SyncService.java │ │ │ ├── NewInstanceService.java │ │ │ ├── SingleService.java │ │ │ └── BatchService.java │ │ │ ├── InstanceManager.java │ │ │ ├── utils │ │ │ ├── CredentialEncryptor.java │ │ │ ├── Defaults.java │ │ │ ├── ShortcutUtils.java │ │ │ ├── PowerUtils.java │ │ │ └── MoreUtils.java │ │ │ ├── task │ │ │ ├── ExtensionInstallTask.java │ │ │ ├── LinkDataTask.java │ │ │ ├── FileMoveTask.java │ │ │ ├── DownloadTask.java │ │ │ └── UpdateCheckTask.java │ │ │ └── repo │ │ │ └── DatabaseHelper.java │ │ └── module-info.java └── test │ └── java │ └── io │ └── beanvortex │ └── bitkip │ ├── utils │ ├── IOUtilsTest.java │ └── DownloadUtilsTest.java │ ├── repo │ └── DownloadsRepoTest.java │ └── controllers │ └── BatchDownloadTest.java ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── ci_cd.yaml ├── gradlew.bat ├── README.md └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "BitKip" -------------------------------------------------------------------------------- /readme-img/batch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/batch.png -------------------------------------------------------------------------------- /readme-img/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/logs.png -------------------------------------------------------------------------------- /readme-img/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/main.png -------------------------------------------------------------------------------- /readme-img/details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/details.png -------------------------------------------------------------------------------- /readme-img/single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/single.png -------------------------------------------------------------------------------- /readme-img/batch-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/batch-list.png -------------------------------------------------------------------------------- /readme-img/extension.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/extension.gif -------------------------------------------------------------------------------- /readme-img/settings-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/settings-1.png -------------------------------------------------------------------------------- /readme-img/settings-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/settings-2.png -------------------------------------------------------------------------------- /readme-img/download-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/download-folder.png -------------------------------------------------------------------------------- /readme-img/queue-scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/queue-scheduler.png -------------------------------------------------------------------------------- /readme-img/queue-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/readme-img/queue-settings.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /extensions/firefox/resources/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/extensions/firefox/resources/icons/logo.png -------------------------------------------------------------------------------- /extensions/firefox/resources/images/popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/extensions/firefox/resources/images/popup.png -------------------------------------------------------------------------------- /extensions/chrome_based/resources/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/extensions/chrome_based/resources/icons/logo.png -------------------------------------------------------------------------------- /extensions/chrome_based/resources/images/popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/extensions/chrome_based/resources/images/popup.png -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/icons/logo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/src/main/resources/io/beanvortex/bitkip/icons/logo.icns -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/icons/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/src/main/resources/io/beanvortex/bitkip/icons/logo.ico -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/src/main/resources/io/beanvortex/bitkip/icons/logo.png -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/icons/drag-and-drop-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/src/main/resources/io/beanvortex/bitkip/icons/drag-and-drop-dark.png -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/icons/drag-and-drop-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeanVortex/BitKip/HEAD/src/main/resources/io/beanvortex/bitkip/icons/drag-and-drop-light.png -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/BatchURLModel.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | import java.util.List; 4 | 5 | public record BatchURLModel(List links) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/Launcher.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip; 2 | 3 | public class Launcher { 4 | public static void main(String[] args) { 5 | BitKip.main(args); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/SingleURLModel.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | public record SingleURLModel(Long fileSize, String filename, 4 | String mimeType, String url, String agent) { 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/exceptions/DeniedException.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.exceptions; 2 | 3 | public class DeniedException extends Exception { 4 | public DeniedException(String message) { 5 | super(message); 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/DownloadStatus.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | public enum DownloadStatus { 4 | Downloading, 5 | Trying, 6 | Paused, 7 | Completed, 8 | Restarting, 9 | Merging 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/config/observers/QueueObserver.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.config.observers; 2 | 3 | import io.beanvortex.bitkip.controllers.interfaces.FXMLController; 4 | 5 | public interface QueueObserver extends FXMLController { 6 | void updateQueue(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/TurnOffMode.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | public enum TurnOffMode { 4 | NOTHING, 5 | SLEEP, 6 | TURN_OFF; 7 | 8 | @Override 9 | public String toString() { 10 | return this.name(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/css/queueSetting.css: -------------------------------------------------------------------------------- 1 | .padding_10{ 2 | -fx-padding: 10; 3 | } 4 | 5 | .bold{ 6 | -fx-font-weight: bold; 7 | } 8 | .title_size{ 9 | -fx-font-size: 20; 10 | } 11 | .line { 12 | -fx-background-color: rgba(85, 85, 85, 0.5); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/UpdateModel.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | import java.util.List; 4 | 5 | public record UpdateModel(String version, Description description, List assets) { 6 | public record Asset(String title, String link, String size) { 7 | } 8 | public record Description(String header, List features){} 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/css/settings.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .settingTile { 4 | -fx-font-size: 15; 5 | -fx-font-weight: bold; 6 | } 7 | 8 | .settingDescription { 9 | -fx-padding: 0 10; 10 | -fx-font-size: 13; 11 | -fx-opacity: 0.9; 12 | } 13 | 14 | .opacity_7{ 15 | -fx-opacity: 0.7; 16 | } 17 | 18 | #circleTheme{ 19 | -fx-cursor: hand; 20 | -fx-border-color: #333; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/controllers/interfaces/FXMLController.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.controllers.interfaces; 2 | 3 | import io.beanvortex.bitkip.config.observers.ThemeObserver; 4 | import javafx.fxml.Initializable; 5 | import javafx.stage.Stage; 6 | 7 | public interface FXMLController extends Initializable, ThemeObserver { 8 | 9 | void initAfterStage(); 10 | 11 | void setStage(Stage stage); 12 | 13 | Stage getStage(); 14 | } -------------------------------------------------------------------------------- /extensions/firefox/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extDesc": {"message": "Open or download several links at once with a simple selection."}, 3 | "actionTitle": {"message": "Start link selection"}, 4 | "usage": {"message": "Select links by drawing rectangles (left click selects, right click deselects).
You can temporarily hide the overlay and scroll the page holding the H key.
Press Enter to send selected links to BitKip"} 5 | } 6 | -------------------------------------------------------------------------------- /extensions/chrome_based/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extDesc": {"message": "Open or download several links at once with a simple selection."}, 3 | "actionTitle": {"message": "Start link selection"}, 4 | "usage": {"message": "Select links by drawing rectangles (left click selects, right click deselects).
You can temporarily hide the overlay and scroll the page holding the H key.
Press Enter to send selected links to BitKip"} 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/api/SyncService.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.api; 2 | 3 | import io.helidon.webserver.Routing; 4 | import io.helidon.webserver.ServerRequest; 5 | import io.helidon.webserver.ServerResponse; 6 | import io.helidon.webserver.Service; 7 | 8 | import static io.beanvortex.bitkip.config.AppConfigs.serverPort; 9 | 10 | public class SyncService implements Service { 11 | @Override 12 | public void update(Routing.Rules rules) { 13 | rules.get("/", this::doGet); 14 | } 15 | 16 | private void doGet(ServerRequest req, ServerResponse res) { 17 | res.status(200).send(serverPort); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/api/NewInstanceService.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.api; 2 | 3 | import io.beanvortex.bitkip.BitKip; 4 | import io.helidon.webserver.Routing; 5 | import io.helidon.webserver.ServerRequest; 6 | import io.helidon.webserver.ServerResponse; 7 | import io.helidon.webserver.Service; 8 | import javafx.application.Platform; 9 | 10 | public class NewInstanceService implements Service { 11 | @Override 12 | public void update(Routing.Rules rules) { 13 | rules.get("/", this::doGet); 14 | } 15 | 16 | private void doGet(ServerRequest req, ServerResponse res) { 17 | Platform.runLater(BitKip::show); 18 | res.status(200); 19 | res.send("OK"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/StartedQueue.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | import javafx.scene.control.MenuItem; 4 | 5 | import java.util.Objects; 6 | 7 | public record StartedQueue(QueueModel queue, MenuItem startItem, MenuItem stopItem) { 8 | 9 | public StartedQueue(QueueModel queue) { 10 | this(queue, null, null); 11 | } 12 | 13 | @Override 14 | public boolean equals(Object o) { 15 | if (this == o) return true; 16 | if (o == null || getClass() != o.getClass()) return false; 17 | StartedQueue that = (StartedQueue) o; 18 | return Objects.equals(queue, that.queue); 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | return Objects.hash(queue); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | ${log.file.path} 10 | 11 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/config/observers/ThemeObserver.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.config.observers; 2 | 3 | import io.beanvortex.bitkip.BitKip; 4 | import javafx.scene.Scene; 5 | 6 | import static io.beanvortex.bitkip.config.AppConfigs.theme; 7 | 8 | public interface ThemeObserver { 9 | default void updateTheme(Scene scene) { 10 | updateThemeNotObserved(scene); 11 | } 12 | 13 | static void updateThemeNotObserved(Scene scene){ 14 | var stylesheets = scene.getStylesheets(); 15 | if (!stylesheets.contains(BitKip.getResource("css/light_mode.css").toExternalForm())) 16 | stylesheets.add(BitKip.getResource("css/light_mode.css").toExternalForm()); 17 | 18 | if (theme.equals("light")) 19 | stylesheets.remove(BitKip.getResource("css/dark_mode.css").toExternalForm()); 20 | else 21 | stylesheets.add(BitKip.getResource("css/dark_mode.css").toExternalForm()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/models/Credentials.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.models; 2 | 3 | import io.beanvortex.bitkip.utils.CredentialEncryptor; 4 | 5 | import java.util.Base64; 6 | 7 | public record Credentials(String username, String password) { 8 | 9 | public boolean isOk() { 10 | return username != null && password != null && !username.isBlank() && !password.isBlank(); 11 | } 12 | 13 | public String base64Encoded() { 14 | return Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); 15 | } 16 | 17 | public String encrypt() { 18 | return CredentialEncryptor.encrypt(username + ":" + password); 19 | } 20 | 21 | public static Credentials decrypt(String encryptedStr) { 22 | try { 23 | var decrypt = CredentialEncryptor.decrypt(encryptedStr).split(":"); 24 | return new Credentials(decrypt[0], decrypt[1]); 25 | } catch (Exception ignore) { 26 | } 27 | return new Credentials(null, null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/InstanceManager.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip; 2 | 3 | import io.beanvortex.bitkip.config.AppConfigs; 4 | 5 | import java.net.URI; 6 | import java.net.http.HttpClient; 7 | import java.net.http.HttpRequest; 8 | import java.net.http.HttpResponse; 9 | import java.time.Duration; 10 | 11 | public class InstanceManager { 12 | public static boolean notifyCurrentInstance() { 13 | try (var client = HttpClient.newBuilder() 14 | .connectTimeout(Duration.ofSeconds(5)) 15 | .build()) { 16 | 17 | var request = HttpRequest.newBuilder() 18 | .uri(URI.create("http://127.0.0.1:" + AppConfigs.serverPort + "/new_instance")) 19 | .GET() 20 | .timeout(Duration.ofSeconds(5)) 21 | .build(); 22 | 23 | var response = client.send(request, HttpResponse.BodyHandlers.ofString()); 24 | return response.statusCode() == 200; 25 | } catch (Exception e) { 26 | 27 | return false; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/config/observers/ThemeSubject.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.config.observers; 2 | 3 | 4 | import io.beanvortex.bitkip.config.AppConfigs; 5 | import javafx.scene.Scene; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class ThemeSubject { 11 | 12 | private final Map observers = new HashMap<>(); 13 | private static final ThemeSubject themeSubject = new ThemeSubject(); 14 | 15 | private ThemeSubject() { 16 | } 17 | 18 | public void addObserver(ThemeObserver o, Scene scene) { 19 | observers.put(o, scene); 20 | } 21 | 22 | public void removeObserver(ThemeObserver o) { 23 | observers.remove(o); 24 | } 25 | 26 | private void notifyAllObservers() { 27 | observers.forEach(ThemeObserver::updateTheme); 28 | } 29 | 30 | 31 | public static void setTheme(String theme) { 32 | AppConfigs.theme = theme; 33 | themeSubject.notifyAllObservers(); 34 | } 35 | 36 | public static ThemeSubject getThemeSubject() { 37 | return themeSubject; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/fxml/newDownload.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/utils/Defaults.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | 7 | public class Defaults { 8 | 9 | public static final String ALL_DOWNLOADS_QUEUE = "All Downloads"; 10 | public static final String COMPRESSED_QUEUE = "Compressed"; 11 | public static final String PROGRAMS_QUEUE = "Programs"; 12 | public static final String VIDEOS_QUEUE = "Videos"; 13 | public static final String DOCS_QUEUE = "Docs"; 14 | public static final String MUSIC_QUEUE = "Music"; 15 | public static final String OTHERS_QUEUE = "Others"; 16 | 17 | public static final List staticQueueNames = List.of(ALL_DOWNLOADS_QUEUE, COMPRESSED_QUEUE, 18 | MUSIC_QUEUE, VIDEOS_QUEUE, PROGRAMS_QUEUE, DOCS_QUEUE, OTHERS_QUEUE); 19 | public static final List allSideTreeStaticNames = new ArrayList<>(staticQueueNames); 20 | 21 | public static final List compressedEx = List.of("rar", "zip", "7z", "deb", "compressed", 22 | "pkg", "rpm", "tar", "tar.gz", "z"); 23 | public static final List programEx = List.of("bin", "dmg", "iso", "msi", 24 | "exe", "sh", "cmd", "apk", "bat", "cgi", "jar", "py", "wsf"); 25 | public static final List videoEx = List.of("mp4", "mov", "mpg", "mpeg", 26 | "mkv", "avi", "flv", "m4v", "h264", "swf", "vob", "webm", "wmv", "3gp"); 27 | public static final List documentEx = List.of("csv", "dat", "db", "sql", 28 | "xml", "html", "htm", "ppt", "odp", "pptx", "pps", "ods", "xls", "xlsm", "xlsx", 29 | "doc", "docx", "odt", "pdf", "rtf", "txt", "tex", "wpd"); 30 | public static final List musicEx = List.of("mp3", "ogg", "wav", "mpa", 31 | "cda", "aif", "mid", "midi", "wma", "wpl"); 32 | 33 | 34 | public static final LinkedHashMap> extensions = new LinkedHashMap<>(); 35 | 36 | static { 37 | extensions.put(COMPRESSED_QUEUE, compressedEx); 38 | extensions.put(PROGRAMS_QUEUE, programEx); 39 | extensions.put(VIDEOS_QUEUE, videoEx); 40 | extensions.put(DOCS_QUEUE, documentEx); 41 | extensions.put(MUSIC_QUEUE, musicEx); 42 | extensions.put(OTHERS_QUEUE, new ArrayList<>()); 43 | allSideTreeStaticNames.addAll(List.of("All", "Categories", "Finished", "Unfinished", "Downloading")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/task/LinkDataTask.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.task; 2 | 3 | import io.beanvortex.bitkip.controllers.BatchDownload; 4 | import io.beanvortex.bitkip.models.Credentials; 5 | import io.beanvortex.bitkip.utils.DownloadUtils; 6 | import io.beanvortex.bitkip.models.LinkModel; 7 | import javafx.concurrent.Task; 8 | import reactor.core.publisher.Flux; 9 | 10 | import java.io.IOException; 11 | import java.net.HttpURLConnection; 12 | import java.util.List; 13 | 14 | 15 | public class LinkDataTask extends Task> { 16 | 17 | private final List links; 18 | private final Credentials credentials; 19 | private boolean cancel; 20 | 21 | public LinkDataTask(List links, Credentials credentials) { 22 | this.links = links; 23 | this.credentials = credentials; 24 | } 25 | 26 | @Override 27 | protected Flux call() { 28 | return Flux.create(fluxSink -> { 29 | for (var lm : links) { 30 | if (cancel) 31 | break; 32 | HttpURLConnection connection; 33 | try { 34 | connection = DownloadUtils.connect(lm.getUri(), credentials); 35 | } catch (IOException e) { 36 | fluxSink.error(new RuntimeException(e)); 37 | return; 38 | } 39 | var uri = lm.getUri(); 40 | var fileSize = DownloadUtils.getFileSize(connection); 41 | var fileName = DownloadUtils.extractFileName(uri, connection); 42 | var secondaryQueue = BatchDownload.getSecondaryQueueByFileName(fileName); 43 | if (lm.getPath() == null || lm.getPath().isEmpty()) { 44 | var path = DownloadUtils.determineLocation(fileName); 45 | lm.setPath(path); 46 | } 47 | lm.setName(DownloadUtils.getNewFileNameIfExists(fileName, lm.getPath())); 48 | lm.setSize(fileSize); 49 | if (!lm.getQueues().contains(secondaryQueue)) 50 | lm.getQueues().add(secondaryQueue); 51 | lm.setResumable(DownloadUtils.canResume(connection)); 52 | fluxSink.next(lm); 53 | } 54 | fluxSink.complete(); 55 | }); 56 | } 57 | 58 | public void setCancel(boolean cancel) { 59 | this.cancel = cancel; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/utils/ShortcutUtils.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.utils; 2 | 3 | import javafx.scene.input.KeyCode; 4 | import javafx.scene.input.KeyCodeCombination; 5 | import javafx.scene.input.KeyCombination; 6 | 7 | public class ShortcutUtils { 8 | 9 | public static final KeyCodeCombination NEW_DOWNLOAD_KEY = new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN); 10 | public static final KeyCodeCombination OPEN_KEY = new KeyCodeCombination(KeyCode.ENTER); 11 | public static final KeyCodeCombination OPEN_FOLDER_KEY = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN); 12 | public static final KeyCodeCombination DETAILS_KEY = new KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN); 13 | public static final KeyCodeCombination NEW_BATCH_KEY = new KeyCodeCombination(KeyCode.B, KeyCombination.CONTROL_DOWN); 14 | public static final KeyCodeCombination SETTINGS_KEY = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN); 15 | public static final KeyCodeCombination QUIT_KEY = new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN); 16 | public static final KeyCodeCombination RESUME_KEY = new KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN); 17 | public static final KeyCodeCombination PAUSE_KEY = new KeyCodeCombination(KeyCode.P, KeyCombination.CONTROL_DOWN); 18 | public static final KeyCodeCombination PAUSE_ALL_KEY = new KeyCodeCombination(KeyCode.P, KeyCombination.SHIFT_DOWN); 19 | public static final KeyCodeCombination RESTART_KEY = new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN); 20 | public static final KeyCodeCombination REFRESH_KEY = new KeyCodeCombination(KeyCode.X, KeyCombination.CONTROL_DOWN); 21 | public static final KeyCodeCombination COPY_KEY = new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_DOWN); 22 | public static final KeyCodeCombination LOCATION_KEY = new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN); 23 | public static final KeyCodeCombination EXPORT_KEY = new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN); 24 | public static final KeyCodeCombination DELETE_FILE_KEY = new KeyCodeCombination(KeyCode.DELETE, KeyCombination.CONTROL_DOWN); 25 | public static final KeyCodeCombination DELETE_KEY = new KeyCodeCombination(KeyCode.DELETE); 26 | public static final KeyCodeCombination NEW_QUEUE_KEY = new KeyCodeCombination(KeyCode.N, KeyCombination.SHIFT_DOWN); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/utils/PowerUtils.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.utils; 2 | 3 | import com.sun.jna.Native; 4 | import io.beanvortex.bitkip.models.TurnOffMode; 5 | 6 | import java.io.IOException; 7 | 8 | import static com.sun.jna.Platform.*; 9 | import static io.beanvortex.bitkip.config.AppConfigs.log; 10 | import static io.beanvortex.bitkip.config.AppConfigs.userPassword; 11 | 12 | public class PowerUtils { 13 | 14 | public static void turnOff(TurnOffMode turnOffMode) { 15 | switch (turnOffMode) { 16 | case SLEEP -> sleep(); 17 | case TURN_OFF -> shutDown(); 18 | } 19 | } 20 | 21 | private static void shutDown() { 22 | try { 23 | log.info("Shutting down"); 24 | if (isWindows()) 25 | Runtime.getRuntime().exec(new String[]{"shutdown", "-s"}); 26 | else { 27 | // isMac() 28 | var command = "sudo,-S,shutdown"; 29 | if (isLinux() || isSolaris() || isFreeBSD() || isOpenBSD()) 30 | command += ",now"; 31 | var pb = new ProcessBuilder(command.split(",")); 32 | var process = pb.start(); 33 | process.getOutputStream().write((userPassword + "\n").getBytes()); 34 | process.getOutputStream().flush(); 35 | } 36 | 37 | } catch (IOException e) { 38 | throw new RuntimeException(e); 39 | } 40 | } 41 | 42 | private static void sleep() { 43 | try { 44 | log.info("Sleeping"); 45 | if (isWindows()) 46 | SetSuspendState(false, false, false); 47 | else { 48 | // isLinux() || isSolaris() || isFreeBSD() || isOpenBSD() 49 | var command = "sudo,-S,systemctl,suspend"; 50 | if (isMac()) 51 | command = "sudo,-S,shutdown,-s"; 52 | var pb = new ProcessBuilder(command.split(",")); 53 | var process = pb.start(); 54 | process.getOutputStream().write((userPassword + "\n").getBytes()); 55 | process.getOutputStream().flush(); 56 | } 57 | } catch (IOException e) { 58 | throw new RuntimeException(e); 59 | } 60 | } 61 | 62 | public static native boolean SetSuspendState(boolean hibernate, boolean forceCritical, boolean disableWakeEvent); 63 | 64 | static { 65 | if (isWindows()) 66 | Native.register("powrprof"); 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/utils/MoreUtils.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.utils; 2 | 3 | import io.beanvortex.bitkip.config.AppConfigs; 4 | import io.beanvortex.bitkip.task.ExtensionInstallTask; 5 | import io.beanvortex.bitkip.task.UpdateCheckTask; 6 | import javafx.application.Platform; 7 | import org.controlsfx.control.Notifications; 8 | 9 | import java.io.IOException; 10 | import java.util.concurrent.Executors; 11 | 12 | import static io.beanvortex.bitkip.config.AppConfigs.log; 13 | 14 | public class MoreUtils { 15 | 16 | public static void checkUpdates(boolean showNoUpdatesNotification) { 17 | var updateChecker = new UpdateCheckTask(); 18 | var executor = Executors.newCachedThreadPool(); 19 | updateChecker.setExecutor(executor); 20 | updateChecker.valueProperty().addListener((obs, old, newVal) -> { 21 | var version = newVal.version(); 22 | if (!AppConfigs.VERSION.equals(version)) { 23 | log.info("New update available: {}", version); 24 | IOUtils.writeUpdateDescription(newVal.description()); 25 | FxUtils.showUpdateDialog(newVal); 26 | } 27 | }); 28 | updateChecker.setOnCancelled(e -> { 29 | if (showNoUpdatesNotification) 30 | Platform.runLater(() -> Notifications.create() 31 | .title("Checked for updates") 32 | .text("No updates available") 33 | .showInformation()); 34 | }); 35 | updateChecker.exceptionProperty().addListener((ob, o, ex) -> { 36 | if (ex instanceof IOException && showNoUpdatesNotification) 37 | Platform.runLater(() -> Notifications.create() 38 | .title("Failed to check updates") 39 | .text("Could not connect to source, check your connection") 40 | .showWarning()); 41 | 42 | }); 43 | executor.submit(updateChecker); 44 | 45 | } 46 | 47 | public static void downloadExtension() { 48 | var exTask = new ExtensionInstallTask(); 49 | var executor = Executors.newCachedThreadPool(); 50 | exTask.setExecutor(executor); 51 | exTask.exceptionProperty().addListener((ob, o, ex) -> { 52 | if (ex instanceof IOException) 53 | Platform.runLater(() -> Notifications.create() 54 | .title("Failed to install extension") 55 | .text("Could not connect to source, check your connection") 56 | .showWarning()); 57 | 58 | }); 59 | executor.submit(exTask); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/beanvortex/bitkip/task/FileMoveTask.java: -------------------------------------------------------------------------------- 1 | package io.beanvortex.bitkip.task; 2 | 3 | import io.beanvortex.bitkip.utils.DownloadUtils; 4 | import io.beanvortex.bitkip.utils.IOUtils; 5 | import io.beanvortex.bitkip.repo.DownloadsRepo; 6 | import javafx.concurrent.Task; 7 | 8 | import java.io.IOException; 9 | import java.util.concurrent.ExecutorService; 10 | 11 | import static io.beanvortex.bitkip.utils.Defaults.ALL_DOWNLOADS_QUEUE; 12 | 13 | public class FileMoveTask extends Task { 14 | 15 | private final String prevPath; 16 | private final String nextPath; 17 | private final long size; 18 | private final ExecutorService executor; 19 | private boolean isCompleted, isCanceled; 20 | 21 | public FileMoveTask(String prevPath, String nextPath, long size, ExecutorService executor) { 22 | this.prevPath = prevPath; 23 | this.nextPath = nextPath; 24 | this.size = size; 25 | this.executor = executor; 26 | } 27 | 28 | @Override 29 | protected Long call() { 30 | calculateSpeedAndProgress(); 31 | IOUtils.moveAndDeletePreviousData(prevPath, nextPath); 32 | DownloadsRepo.getDownloadsByQueueName(ALL_DOWNLOADS_QUEUE, false).forEach(dm -> { 33 | if (dm.getFilePath().contains("BitKip")) { 34 | var downloadPath = DownloadUtils.determineLocation(dm.getName()); 35 | var id = dm.getId(); 36 | DownloadsRepo.updateDownloadLocation(downloadPath, id); 37 | } 38 | }); 39 | isCompleted = true; 40 | executor.shutdownNow(); 41 | if (size == 0) 42 | updateProgress(1.0d, 1.0d); 43 | return size; 44 | } 45 | 46 | private void calculateSpeedAndProgress() { 47 | if (size != 0) 48 | executor.submit(() -> { 49 | Thread.currentThread().setName("calculator: " + Thread.currentThread().getName()); 50 | try { 51 | while (!isCompleted || !isCanceled) { 52 | var currentFileSize = IOUtils.getFolderSize(nextPath); 53 | updateProgress(currentFileSize, size); 54 | updateValue(currentFileSize); 55 | } 56 | } catch (IOException e) { 57 | throw new RuntimeException(e); 58 | } 59 | }); 60 | } 61 | 62 | public void pause() { 63 | isCanceled = true; 64 | } 65 | 66 | public boolean isCompleted() { 67 | return isCompleted; 68 | } 69 | 70 | public String getPrevPath() { 71 | return prevPath; 72 | } 73 | 74 | public String getNextPath() { 75 | return nextPath; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/resources/io/beanvortex/bitkip/fxml/batchList.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |