Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions submissions/WebCLBrowser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# CommandLine Web Browser
A simple command-line web browser, written in Java, using Lanterna and Jsoup.\
Most web pages can be read in a simplistic state, though Cloudflare seems to block access to some pages.
The interface has a traditional browser toolbar at the top, with forward and back arrows, etc.
![example](https://www.wiicart.net/img/clbrowser.png)

# How To Run
Download the JAR file locally, which can be found [here](https://github.com/Wiicart/CommandLineWebBrowser/releases),
[here](https://www.wiicart.net/clbrowser/clbrowser-1.0.jar), or in this directory.
- Example Command: `curl -L -O -A "Mozilla/5.0" https://www.wiicart.net/clbrowser/clbrowser-1.0.jar`
- On Linux or Mac, run `java -jar <path-to-clbrowser-1.0.jar>`. If using windows, use `javaw`.

The program relies on the Lanterna, Jsoup and Jfiglet libraries, but they are shaded into the JAR, so no action is needed.

# Why
I created this because when I'm ssh-ing into servers of mine, I usually have a browser open in the next window for references.
I figured a program like this could be useful for quickly glancing at a webpage without having to switch windows.
Binary file added submissions/WebCLBrowser/clbrowser-1.0.jar
Binary file not shown.
70 changes: 70 additions & 0 deletions submissions/WebCLBrowser/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.wiicart.webcli</groupId>
<artifactId>CLIWebBrowser</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>net.wiicart.webcli.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.googlecode.lanterna</groupId>
<artifactId>lanterna</artifactId>
<version>3.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>26.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<!-- jsoup HTML parser library @ https://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.20.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.lalyos</groupId>
<artifactId>jfiglet</artifactId>
<version>0.0.9</version>
<scope>compile</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package net.wiicart.webcli;

import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.Terminal;
import net.wiicart.webcli.screen.WebPageScreen;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public final class CLIWebBrowser {

public CLIWebBrowser() {
try (Terminal terminal = createTerminalAndInit()){
terminal.setBackgroundColor(TextColor.ANSI.RED);
Screen screen = createScreen();
screen.startScreen();
MultiWindowTextGUI gui = new MultiWindowTextGUI(screen);
WebPageScreen screen1 = new WebPageScreen(gui);
screen1.show();
terminal.exitPrivateMode();
terminal.flush();
} catch(IOException e) {
throw new RuntimeException(e);
}
}

private @NotNull Terminal createTerminalAndInit() {
try {
DefaultTerminalFactory factory = new DefaultTerminalFactory();
Terminal terminal = factory.createTerminal();
terminal.enterPrivateMode();
return terminal;
} catch(IOException e) {
throw new RuntimeException(e);
}
}

private @NotNull Screen createScreen() {
try {
DefaultTerminalFactory factory = new DefaultTerminalFactory();
return factory.createScreen();
} catch(IOException e) {
throw new RuntimeException(e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.wiicart.webcli;

public class Main {
public static void main(String[] args) {
new CLIWebBrowser(); // initialize program
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package net.wiicart.webcli.screen;

import org.jetbrains.annotations.MustBeInvokedByOverriders;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractScreen<T extends AbstractScreen<T>> {

public abstract ScreenFutureRunner<T> show();

//todo remove, uneccessarry
abstract boolean readyToExecute();

/**
* Class that manages Future Runnables to be executed once a Page has served its purpose.
* @param <T> The type this was obtained from
*/
public static final class ScreenFutureRunner<T extends AbstractScreen<T>> {

private final T screen;

private final List<Runnable> runnables = new ArrayList<>();

ScreenFutureRunner(T screen) {
this.screen = screen;
}

public final ScreenFutureRunner<T> then(Runnable runnable) {
if (screen.readyToExecute()) {
runnable.run();
} else {
runnables.add(runnable);
}
return this;
}


@MustBeInvokedByOverriders
void executeRunnables() {
for (Runnable runnable : runnables) {
runnable.run();
}
runnables.clear();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.wiicart.webcli.screen;

import com.googlecode.lanterna.gui2.ProgressBar;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import org.jetbrains.annotations.NotNull;

/**
* Represents a loading screen, used before a page is loaded.
*/
public final class LoadingScreen extends AbstractScreen<LoadingScreen> {

private final @NotNull WindowBasedTextGUI gui;
private final @NotNull ProgressBar progressBar;

private ScreenFutureRunner<LoadingScreen> future;

public LoadingScreen(@NotNull WindowBasedTextGUI gui) {
this.gui = gui;
progressBar = new ProgressBar();
future = new ScreenFutureRunner<>(this);


}

@Override
public ScreenFutureRunner<LoadingScreen> show() {
return future;
}

@Override
boolean readyToExecute() {
return false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package net.wiicart.webcli.screen;

import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.Borders;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.Direction;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.LinearLayout;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.TextBox;
import com.googlecode.lanterna.gui2.Window;
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import org.jetbrains.annotations.NotNull;

import java.util.Set;

public final class URLEntryScreen extends AbstractScreen<URLEntryScreen> {

private static final Set<Window.Hint> ENTRY_HINTS = Set.of(Window.Hint.CENTERED, Window.Hint.FIT_TERMINAL_WINDOW);

private final WindowBasedTextGUI gui;
private final TextBox textBox = new TextBox(new TerminalSize(50, 1));
private String entry; // The URL that was entered
private boolean execute = false;

private final ScreenFutureRunner<URLEntryScreen> future;

public URLEntryScreen(@NotNull WindowBasedTextGUI gui) {
this.gui = gui;
future = new ScreenFutureRunner<>(this);
initTextBox();
// Do not call show() here
}

private void initTextBox() {
textBox.withBorder(Borders.singleLine("Enter your URL:"));
}

public ScreenFutureRunner<URLEntryScreen> show() {
Window window = createWindow();
gui.addWindowAndWait(window);
execute = true;
return future;
}

private @NotNull Panel createEntryPanel(Window window) {
Panel panel = new Panel();
panel.setLayoutManager(new LinearLayout(Direction.VERTICAL));
panel.setSize(new TerminalSize(25, 6));
panel.addComponent(new Label("Enter a URL:"));
panel.addComponent(textBox);
panel.addComponent(new Button("Go", () -> {
entry = textBox.getText();
future.executeRunnables();
window.close();
}));
return panel;
}

private @NotNull Window createWindow() {
BasicWindow window = new BasicWindow("CLI Web Browser");
window.setTitle("Web Browser");
window.setComponent(createEntryPanel(window));
window.setHints(ENTRY_HINTS);
return window;
}

public String getEntry() {
return entry;
}

@Override
boolean readyToExecute() {
return execute;
}
}
Loading