1
0
mirror of https://github.com/RipMeApp/ripme.git synced 2025-08-12 00:44:03 +02:00

Merge pull request #1406 from Isaaku/issues/location_fix

location fix
This commit is contained in:
cyian-1756
2019-08-30 14:57:19 -05:00
committed by GitHub
22 changed files with 572 additions and 382 deletions

View File

@@ -20,17 +20,14 @@ import com.rarchives.ripme.ui.RipStatusMessage.STATUS;
import com.rarchives.ripme.utils.Utils; import com.rarchives.ripme.utils.Utils;
/** /**
* Thread for downloading files. * Thread for downloading files. Includes retry logic, observer notifications,
* Includes retry logic, observer notifications, and other goodies. * and other goodies.
*/ */
class DownloadFileThread extends Thread { class DownloadFileThread extends Thread {
private ResourceBundle rb = MainWindow.rb;
private static final Logger logger = Logger.getLogger(DownloadFileThread.class); private static final Logger logger = Logger.getLogger(DownloadFileThread.class);
private String referrer = ""; private String referrer = "";
private Map<String,String> cookies = new HashMap<>(); private Map<String, String> cookies = new HashMap<>();
private URL url; private URL url;
private File saveAs; private File saveAs;
@@ -55,18 +52,19 @@ class DownloadFileThread extends Thread {
public void setReferrer(String referrer) { public void setReferrer(String referrer) {
this.referrer = referrer; this.referrer = referrer;
} }
public void setCookies(Map<String,String> cookies) {
public void setCookies(Map<String, String> cookies) {
this.cookies = cookies; this.cookies = cookies;
} }
/** /**
* Attempts to download the file. Retries as needed. * Attempts to download the file. Retries as needed. Notifies observers upon
* Notifies observers upon completion/error/warn. * completion/error/warn.
*/ */
public void run() { public void run() {
// First thing we make sure the file name doesn't have any illegal chars in it // First thing we make sure the file name doesn't have any illegal chars in it
saveAs = new File(saveAs.getParentFile().getAbsolutePath() + File.separator + Utils.sanitizeSaveAs(saveAs.getName())); saveAs = new File(
saveAs.getParentFile().getAbsolutePath() + File.separator + Utils.sanitizeSaveAs(saveAs.getName()));
long fileSize = 0; long fileSize = 0;
int bytesTotal = 0; int bytesTotal = 0;
int bytesDownloaded = 0; int bytesDownloaded = 0;
@@ -76,16 +74,18 @@ class DownloadFileThread extends Thread {
try { try {
observer.stopCheck(); observer.stopCheck();
} catch (IOException e) { } catch (IOException e) {
observer.downloadErrored(url, rb.getString("download.interrupted")); observer.downloadErrored(url, Utils.getLocalizedString("download.interrupted"));
return; return;
} }
if (saveAs.exists() && !observer.tryResumeDownload() && !getFileExtFromMIME || if (saveAs.exists() && !observer.tryResumeDownload() && !getFileExtFromMIME
Utils.fuzzyExists(new File(saveAs.getParent()), saveAs.getName()) && getFileExtFromMIME && !observer.tryResumeDownload()) { || Utils.fuzzyExists(new File(saveAs.getParent()), saveAs.getName()) && getFileExtFromMIME
&& !observer.tryResumeDownload()) {
if (Utils.getConfigBoolean("file.overwrite", false)) { if (Utils.getConfigBoolean("file.overwrite", false)) {
logger.info("[!] " + rb.getString("deleting.existing.file") + prettySaveAs); logger.info("[!] " + Utils.getLocalizedString("deleting.existing.file") + prettySaveAs);
saveAs.delete(); saveAs.delete();
} else { } else {
logger.info("[!] " + rb.getString("skipping") + url + " -- " + rb.getString("file.already.exists") + ": " + prettySaveAs); logger.info("[!] " + Utils.getLocalizedString("skipping") + url + " -- "
+ Utils.getLocalizedString("file.already.exists") + ": " + prettySaveAs);
observer.downloadExists(url, saveAs); observer.downloadExists(url, saveAs);
return; return;
} }
@@ -95,7 +95,8 @@ class DownloadFileThread extends Thread {
int tries = 0; // Number of attempts to download int tries = 0; // Number of attempts to download
do { do {
tries += 1; tries += 1;
InputStream bis = null; OutputStream fos = null; InputStream bis = null;
OutputStream fos = null;
try { try {
logger.info(" Downloading file: " + urlToDownload + (tries > 0 ? " Retry #" + tries : "")); logger.info(" Downloading file: " + urlToDownload + (tries > 0 ? " Retry #" + tries : ""));
observer.sendUpdate(STATUS.DOWNLOAD_STARTED, url.toExternalForm()); observer.sendUpdate(STATUS.DOWNLOAD_STARTED, url.toExternalForm());
@@ -104,16 +105,16 @@ class DownloadFileThread extends Thread {
HttpURLConnection huc; HttpURLConnection huc;
if (this.url.toString().startsWith("https")) { if (this.url.toString().startsWith("https")) {
huc = (HttpsURLConnection) urlToDownload.openConnection(); huc = (HttpsURLConnection) urlToDownload.openConnection();
} } else {
else {
huc = (HttpURLConnection) urlToDownload.openConnection(); huc = (HttpURLConnection) urlToDownload.openConnection();
} }
huc.setInstanceFollowRedirects(true); huc.setInstanceFollowRedirects(true);
// It is important to set both ConnectTimeout and ReadTimeout. If you don't then ripme will wait forever // It is important to set both ConnectTimeout and ReadTimeout. If you don't then
// ripme will wait forever
// for the server to send data after connecting. // for the server to send data after connecting.
huc.setConnectTimeout(TIMEOUT); huc.setConnectTimeout(TIMEOUT);
huc.setReadTimeout(TIMEOUT); huc.setReadTimeout(TIMEOUT);
huc.setRequestProperty("accept", "*/*"); huc.setRequestProperty("accept", "*/*");
if (!referrer.equals("")) { if (!referrer.equals("")) {
huc.setRequestProperty("Referer", referrer); // Sic huc.setRequestProperty("Referer", referrer); // Sic
} }
@@ -131,17 +132,18 @@ class DownloadFileThread extends Thread {
huc.setRequestProperty("Range", "bytes=" + fileSize + "-"); huc.setRequestProperty("Range", "bytes=" + fileSize + "-");
} }
} }
logger.debug(rb.getString("request.properties") + ": " + huc.getRequestProperties()); logger.debug(Utils.getLocalizedString("request.properties") + ": " + huc.getRequestProperties());
huc.connect(); huc.connect();
int statusCode = huc.getResponseCode(); int statusCode = huc.getResponseCode();
logger.debug("Status code: " + statusCode); logger.debug("Status code: " + statusCode);
// If the server doesn't allow resuming downloads error out // If the server doesn't allow resuming downloads error out
if (statusCode != 206 && observer.tryResumeDownload() && saveAs.exists()) { if (statusCode != 206 && observer.tryResumeDownload() && saveAs.exists()) {
// TODO find a better way to handle servers that don't support resuming downloads then just erroring out // TODO find a better way to handle servers that don't support resuming
throw new IOException(rb.getString("server.doesnt.support.resuming.downloads")); // downloads then just erroring out
throw new IOException(Utils.getLocalizedString("server.doesnt.support.resuming.downloads"));
} }
if (statusCode / 100 == 3) { // 3xx Redirect if (statusCode / 100 == 3) { // 3xx Redirect
if (!redirected) { if (!redirected) {
// Don't increment retries on the first redirect // Don't increment retries on the first redirect
tries--; tries--;
@@ -153,14 +155,17 @@ class DownloadFileThread extends Thread {
throw new IOException("Redirect status code " + statusCode + " - redirect to " + location); throw new IOException("Redirect status code " + statusCode + " - redirect to " + location);
} }
if (statusCode / 100 == 4) { // 4xx errors if (statusCode / 100 == 4) { // 4xx errors
logger.error("[!] " + rb.getString("nonretriable.status.code") + " " + statusCode + " while downloading from " + url); logger.error("[!] " + Utils.getLocalizedString("nonretriable.status.code") + " " + statusCode
observer.downloadErrored(url, rb.getString("nonretriable.status.code") + " " + statusCode + " while downloading " + url.toExternalForm()); + " while downloading from " + url);
observer.downloadErrored(url, Utils.getLocalizedString("nonretriable.status.code") + " "
+ statusCode + " while downloading " + url.toExternalForm());
return; // Not retriable, drop out. return; // Not retriable, drop out.
} }
if (statusCode / 100 == 5) { // 5xx errors if (statusCode / 100 == 5) { // 5xx errors
observer.downloadErrored(url, rb.getString("retriable.status.code") + " " + statusCode + " while downloading " + url.toExternalForm()); observer.downloadErrored(url, Utils.getLocalizedString("retriable.status.code") + " " + statusCode
+ " while downloading " + url.toExternalForm());
// Throw exception so download can be retried // Throw exception so download can be retried
throw new IOException(rb.getString("retriable.status.code") + " " + statusCode); throw new IOException(Utils.getLocalizedString("retriable.status.code") + " " + statusCode);
} }
if (huc.getContentLength() == 503 && urlToDownload.getHost().endsWith("imgur.com")) { if (huc.getContentLength() == 503 && urlToDownload.getHost().endsWith("imgur.com")) {
// Imgur image with 503 bytes is "404" // Imgur image with 503 bytes is "404"
@@ -169,7 +174,8 @@ class DownloadFileThread extends Thread {
return; return;
} }
// If the ripper is using the bytes progress bar set bytesTotal to huc.getContentLength() // If the ripper is using the bytes progress bar set bytesTotal to
// huc.getContentLength()
if (observer.useByteProgessBar()) { if (observer.useByteProgessBar()) {
bytesTotal = huc.getContentLength(); bytesTotal = huc.getContentLength();
observer.setBytesTotal(bytesTotal); observer.setBytesTotal(bytesTotal);
@@ -190,14 +196,15 @@ class DownloadFileThread extends Thread {
logger.error("Was unable to get content type from stream"); logger.error("Was unable to get content type from stream");
// Try to get the file type from the magic number // Try to get the file type from the magic number
byte[] magicBytes = new byte[8]; byte[] magicBytes = new byte[8];
bis.read(magicBytes,0, 5); bis.read(magicBytes, 0, 5);
bis.reset(); bis.reset();
fileExt = Utils.getEXTFromMagic(magicBytes); fileExt = Utils.getEXTFromMagic(magicBytes);
if (fileExt != null) { if (fileExt != null) {
saveAs = new File(saveAs.toString() + "." + fileExt); saveAs = new File(saveAs.toString() + "." + fileExt);
} else { } else {
logger.error(rb.getString("was.unable.to.get.content.type.using.magic.number")); logger.error(Utils.getLocalizedString("was.unable.to.get.content.type.using.magic.number"));
logger.error(rb.getString("magic.number.was") + ": " + Arrays.toString(magicBytes)); logger.error(
Utils.getLocalizedString("magic.number.was") + ": " + Arrays.toString(magicBytes));
} }
} }
} }
@@ -210,21 +217,26 @@ class DownloadFileThread extends Thread {
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// We do this because some filesystems have a max name length // We do this because some filesystems have a max name length
if (e.getMessage().contains("File name too long")) { if (e.getMessage().contains("File name too long")) {
logger.error("The filename " + saveAs.getName() + " is to long to be saved on this file system."); logger.error("The filename " + saveAs.getName()
+ " is to long to be saved on this file system.");
logger.info("Shortening filename"); logger.info("Shortening filename");
String[] saveAsSplit = saveAs.getName().split("\\."); String[] saveAsSplit = saveAs.getName().split("\\.");
// Get the file extension so when we shorten the file name we don't cut off the file extension // Get the file extension so when we shorten the file name we don't cut off the
// file extension
String fileExt = saveAsSplit[saveAsSplit.length - 1]; String fileExt = saveAsSplit[saveAsSplit.length - 1];
// The max limit for filenames on Linux with Ext3/4 is 255 bytes // The max limit for filenames on Linux with Ext3/4 is 255 bytes
logger.info(saveAs.getName().substring(0, 254 - fileExt.length()) + fileExt); logger.info(saveAs.getName().substring(0, 254 - fileExt.length()) + fileExt);
String filename = saveAs.getName().substring(0, 254 - fileExt.length()) + "." + fileExt; String filename = saveAs.getName().substring(0, 254 - fileExt.length()) + "." + fileExt;
// We can't just use the new file name as the saveAs because the file name doesn't include the // We can't just use the new file name as the saveAs because the file name
// doesn't include the
// users save path, so we get the user save path from the old saveAs // users save path, so we get the user save path from the old saveAs
saveAs = new File(saveAs.getParentFile().getAbsolutePath() + File.separator + filename); saveAs = new File(saveAs.getParentFile().getAbsolutePath() + File.separator + filename);
fos = new FileOutputStream(saveAs); fos = new FileOutputStream(saveAs);
} else if (saveAs.getAbsolutePath().length() > 259 && Utils.isWindows()) { } else if (saveAs.getAbsolutePath().length() > 259 && Utils.isWindows()) {
// This if is for when the file path has gone above 260 chars which windows does not allow // This if is for when the file path has gone above 260 chars which windows does
fos = new FileOutputStream(Utils.shortenSaveAsWindows(saveAs.getParentFile().getPath(), saveAs.getName())); // not allow
fos = new FileOutputStream(
Utils.shortenSaveAsWindows(saveAs.getParentFile().getPath(), saveAs.getName()));
} }
} }
} }
@@ -239,7 +251,7 @@ class DownloadFileThread extends Thread {
try { try {
observer.stopCheck(); observer.stopCheck();
} catch (IOException e) { } catch (IOException e) {
observer.downloadErrored(url, rb.getString("download.interrupted")); observer.downloadErrored(url, Utils.getLocalizedString("download.interrupted"));
return; return;
} }
fos.write(data, 0, bytesRead); fos.write(data, 0, bytesRead);
@@ -259,27 +271,37 @@ class DownloadFileThread extends Thread {
// Download failed, break out of loop // Download failed, break out of loop
break; break;
} catch (HttpStatusException hse) { } catch (HttpStatusException hse) {
logger.debug(rb.getString("http.status.exception"), hse); logger.debug(Utils.getLocalizedString("http.status.exception"), hse);
logger.error("[!] HTTP status " + hse.getStatusCode() + " while downloading from " + urlToDownload); logger.error("[!] HTTP status " + hse.getStatusCode() + " while downloading from " + urlToDownload);
if (hse.getStatusCode() == 404 && Utils.getConfigBoolean("errors.skip404", false)) { if (hse.getStatusCode() == 404 && Utils.getConfigBoolean("errors.skip404", false)) {
observer.downloadErrored(url, "HTTP status code " + hse.getStatusCode() + " while downloading " + url.toExternalForm()); observer.downloadErrored(url,
"HTTP status code " + hse.getStatusCode() + " while downloading " + url.toExternalForm());
return; return;
} }
} catch (IOException e) { } catch (IOException e) {
logger.debug("IOException", e); logger.debug("IOException", e);
logger.error("[!] " + rb.getString("exception.while.downloading.file") + ": " + url + " - " + e.getMessage()); logger.error("[!] " + Utils.getLocalizedString("exception.while.downloading.file") + ": " + url + " - "
+ e.getMessage());
} finally { } finally {
// Close any open streams // Close any open streams
try { try {
if (bis != null) { bis.close(); } if (bis != null) {
} catch (IOException e) { } bis.close();
}
} catch (IOException e) {
}
try { try {
if (fos != null) { fos.close(); } if (fos != null) {
} catch (IOException e) { } fos.close();
}
} catch (IOException e) {
}
} }
if (tries > this.retries) { if (tries > this.retries) {
logger.error("[!] " + rb.getString ("exceeded.maximum.retries") + " (" + this.retries + ") for URL " + url); logger.error("[!] " + Utils.getLocalizedString("exceeded.maximum.retries") + " (" + this.retries
observer.downloadErrored(url, rb.getString("failed.to.download") + " " + url.toExternalForm()); + ") for URL " + url);
observer.downloadErrored(url,
Utils.getLocalizedString("failed.to.download") + " " + url.toExternalForm());
return; return;
} }
} while (true); } while (true);

View File

@@ -10,13 +10,15 @@ import javax.swing.Action;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import javax.swing.JTable; import javax.swing.JTable;
import com.rarchives.ripme.utils.Utils;
class HistoryMenuMouseListener extends MouseAdapter { class HistoryMenuMouseListener extends MouseAdapter {
private JPopupMenu popup = new JPopupMenu(); private JPopupMenu popup = new JPopupMenu();
private JTable tableComponent; private JTable tableComponent;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public HistoryMenuMouseListener() { public HistoryMenuMouseListener() {
Action checkAllAction = new AbstractAction("Check All") { Action checkAllAction = new AbstractAction(Utils.getLocalizedString("history.check.all")) {
@Override @Override
public void actionPerformed(ActionEvent ae) { public void actionPerformed(ActionEvent ae) {
for (int row = 0; row < tableComponent.getRowCount(); row++) { for (int row = 0; row < tableComponent.getRowCount(); row++) {
@@ -26,7 +28,7 @@ class HistoryMenuMouseListener extends MouseAdapter {
}; };
popup.add(checkAllAction); popup.add(checkAllAction);
Action uncheckAllAction = new AbstractAction("Check None") { Action uncheckAllAction = new AbstractAction(Utils.getLocalizedString("history.check.none")) {
@Override @Override
public void actionPerformed(ActionEvent ae) { public void actionPerformed(ActionEvent ae) {
for (int row = 0; row < tableComponent.getRowCount(); row++) { for (int row = 0; row < tableComponent.getRowCount(); row++) {
@@ -38,7 +40,7 @@ class HistoryMenuMouseListener extends MouseAdapter {
popup.addSeparator(); popup.addSeparator();
Action checkSelected = new AbstractAction("Check Selected") { Action checkSelected = new AbstractAction(Utils.getLocalizedString("history.check.selected")) {
@Override @Override
public void actionPerformed(ActionEvent ae) { public void actionPerformed(ActionEvent ae) {
for (int row : tableComponent.getSelectedRows()) { for (int row : tableComponent.getSelectedRows()) {
@@ -48,7 +50,7 @@ class HistoryMenuMouseListener extends MouseAdapter {
}; };
popup.add(checkSelected); popup.add(checkSelected);
Action uncheckSelected = new AbstractAction("Uncheck Selected") { Action uncheckSelected = new AbstractAction(Utils.getLocalizedString("history.uncheck.selected")) {
@Override @Override
public void actionPerformed(ActionEvent ae) { public void actionPerformed(ActionEvent ae) {
for (int row : tableComponent.getSelectedRows()) { for (int row : tableComponent.getSelectedRows()) {

View File

@@ -71,8 +71,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private static JFrame mainFrame; private static JFrame mainFrame;
private static JTextField ripTextfield; private static JTextField ripTextfield;
private static JButton ripButton, private static JButton ripButton, stopButton;
stopButton;
private static JLabel statusLabel; private static JLabel statusLabel;
private static JButton openButton; private static JButton openButton;
@@ -93,14 +92,13 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private static JPanel historyPanel; private static JPanel historyPanel;
private static JTable historyTable; private static JTable historyTable;
private static AbstractTableModel historyTableModel; private static AbstractTableModel historyTableModel;
private static JButton historyButtonRemove, private static JButton historyButtonRemove, historyButtonClear, historyButtonRerip;
historyButtonClear,
historyButtonRerip;
// Queue // Queue
public static JButton optionQueue; public static JButton optionQueue;
private static JPanel queuePanel; private static JPanel queuePanel;
private static DefaultListModel queueListModel; private static DefaultListModel<Object> queueListModel;
private static QueueMenuMouseListener queueMenuMouseListener;
// Configuration // Configuration
private static JButton optionConfiguration; private static JButton optionConfiguration;
@@ -141,34 +139,19 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private static AbstractRipper ripper; private static AbstractRipper ripper;
public static ResourceBundle rb = Utils.getResourceBundle(null); private void updateQueue(DefaultListModel<Object> model) {
if (model == null)
model = queueListModel;
// All the langs ripme has been translated into Utils.setConfigList("Queue", (Enumeration<Object>) model.elements());
private static String[] supportedLanges = new String[] {
"de_DE",
"ar_AR",
"en_US",
"es_ES",
"fi_FI",
"fr_CH",
"in_ID",
"it_IT",
"kr_KR",
"nl_NL",
"pl_PL",
"porrisavvo_FI",
"pt_BR",
"pt_PT",
"ru_RU"};
private void updateQueueLabel() { MainWindow.optionQueue.setText(String.format("%s%s", Utils.getLocalizedString("queue"),
if (queueListModel.size() > 0) { model.size() == 0 ? "" : "(" + model.size() + ")"));
optionQueue.setText(rb.getString("Queue") + " (" + queueListModel.size() + ")");
} else {
optionQueue.setText(rb.getString("Queue"));
}
} }
private void updateQueue() {
updateQueue(null);
}
private static void addCheckboxListener(JCheckBox checkBox, String configString) { private static void addCheckboxListener(JCheckBox checkBox, String configString) {
checkBox.addActionListener(arg0 -> { checkBox.addActionListener(arg0 -> {
@@ -185,7 +168,6 @@ public final class MainWindow implements Runnable, RipStatusHandler {
return checkbox; return checkbox;
} }
public static void addUrlToQueue(String url) { public static void addUrlToQueue(String url) {
queueListModel.addElement(url); queueListModel.addElement(url);
} }
@@ -276,29 +258,32 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
private boolean isCollapsed() { private boolean isCollapsed() {
return (!logPanel.isVisible() && return (!logPanel.isVisible() && !historyPanel.isVisible() && !queuePanel.isVisible()
!historyPanel.isVisible() && && !configurationPanel.isVisible());
!queuePanel.isVisible() &&
!configurationPanel.isVisible()
);
} }
private void createUI(Container pane) { private void createUI(Container pane) {
//If creating the tray icon fails, ignore it. // If creating the tray icon fails, ignore it.
try { try {
setupTrayIcon(); setupTrayIcon();
} catch (Exception e) { } } catch (Exception e) {
}
EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5); EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5);
GridBagConstraints gbc = new GridBagConstraints(); GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1; gbc.ipadx = 2; gbc.gridx = 0; gbc.weightx = 1;
gbc.weighty = 0; gbc.ipady = 2; gbc.gridy = 0; gbc.ipadx = 2;
gbc.gridx = 0;
gbc.weighty = 0;
gbc.ipady = 2;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.PAGE_START; gbc.anchor = GridBagConstraints.PAGE_START;
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) { } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException
| IllegalAccessException e) {
LOGGER.error("[!] Exception setting system theme:", e); LOGGER.error("[!] Exception setting system theme:", e);
} }
@@ -311,31 +296,38 @@ public final class MainWindow implements Runnable, RipStatusHandler {
try { try {
Image stopIcon = ImageIO.read(getClass().getClassLoader().getResource("stop.png")); Image stopIcon = ImageIO.read(getClass().getClassLoader().getResource("stop.png"));
stopButton.setIcon(new ImageIcon(stopIcon)); stopButton.setIcon(new ImageIcon(stopIcon));
} catch (Exception ignored) { } } catch (Exception ignored) {
}
JPanel ripPanel = new JPanel(new GridBagLayout()); JPanel ripPanel = new JPanel(new GridBagLayout());
ripPanel.setBorder(emptyBorder); ripPanel.setBorder(emptyBorder);
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0; gbc.weightx = 0;
gbc.gridx = 0; ripPanel.add(new JLabel("URL:", JLabel.RIGHT), gbc); gbc.gridx = 0;
ripPanel.add(new JLabel("URL:", JLabel.RIGHT), gbc);
gbc.weightx = 1; gbc.weightx = 1;
gbc.weighty = 1; gbc.weighty = 1;
gbc.gridx = 1; ripPanel.add(ripTextfield, gbc); gbc.gridx = 1;
ripPanel.add(ripTextfield, gbc);
gbc.weighty = 0; gbc.weighty = 0;
gbc.weightx = 0; gbc.weightx = 0;
gbc.gridx = 2; ripPanel.add(ripButton, gbc); gbc.gridx = 2;
gbc.gridx = 3; ripPanel.add(stopButton, gbc); ripPanel.add(ripButton, gbc);
gbc.gridx = 3;
ripPanel.add(stopButton, gbc);
gbc.weightx = 1; gbc.weightx = 1;
statusLabel = new JLabel(rb.getString("inactive")); statusLabel = new JLabel(Utils.getLocalizedString("inactive"));
statusLabel.setHorizontalAlignment(JLabel.CENTER); statusLabel.setHorizontalAlignment(JLabel.CENTER);
openButton = new JButton(); openButton = new JButton();
openButton.setVisible(false); openButton.setVisible(false);
JPanel statusPanel = new JPanel(new GridBagLayout()); JPanel statusPanel = new JPanel(new GridBagLayout());
statusPanel.setBorder(emptyBorder); statusPanel.setBorder(emptyBorder);
gbc.gridx = 0; statusPanel.add(statusLabel, gbc); gbc.gridx = 0;
gbc.gridy = 1; statusPanel.add(openButton, gbc); statusPanel.add(statusLabel, gbc);
gbc.gridy = 1;
statusPanel.add(openButton, gbc);
gbc.gridy = 0; gbc.gridy = 0;
JPanel progressPanel = new JPanel(new GridBagLayout()); JPanel progressPanel = new JPanel(new GridBagLayout());
@@ -345,10 +337,10 @@ public final class MainWindow implements Runnable, RipStatusHandler {
JPanel optionsPanel = new JPanel(new GridBagLayout()); JPanel optionsPanel = new JPanel(new GridBagLayout());
optionsPanel.setBorder(emptyBorder); optionsPanel.setBorder(emptyBorder);
optionLog = new JButton(rb.getString("Log")); optionLog = new JButton(Utils.getLocalizedString("Log"));
optionHistory = new JButton(rb.getString("History")); optionHistory = new JButton(Utils.getLocalizedString("History"));
optionQueue = new JButton(rb.getString("Queue")); optionQueue = new JButton(Utils.getLocalizedString("queue"));
optionConfiguration = new JButton(rb.getString("Configuration")); optionConfiguration = new JButton(Utils.getLocalizedString("Configuration"));
optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
optionQueue.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionQueue.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
@@ -363,11 +355,16 @@ public final class MainWindow implements Runnable, RipStatusHandler {
optionQueue.setIcon(new ImageIcon(icon)); optionQueue.setIcon(new ImageIcon(icon));
icon = ImageIO.read(getClass().getClassLoader().getResource("gear.png")); icon = ImageIO.read(getClass().getClassLoader().getResource("gear.png"));
optionConfiguration.setIcon(new ImageIcon(icon)); optionConfiguration.setIcon(new ImageIcon(icon));
} catch (Exception e) { } } catch (Exception e) {
gbc.gridx = 0; optionsPanel.add(optionLog, gbc); }
gbc.gridx = 1; optionsPanel.add(optionHistory, gbc); gbc.gridx = 0;
gbc.gridx = 2; optionsPanel.add(optionQueue, gbc); optionsPanel.add(optionLog, gbc);
gbc.gridx = 3; optionsPanel.add(optionConfiguration, gbc); gbc.gridx = 1;
optionsPanel.add(optionHistory, gbc);
gbc.gridx = 2;
optionsPanel.add(optionQueue, gbc);
gbc.gridx = 3;
optionsPanel.add(optionConfiguration, gbc);
logPanel = new JPanel(new GridBagLayout()); logPanel = new JPanel(new GridBagLayout());
logPanel.setBorder(emptyBorder); logPanel.setBorder(emptyBorder);
@@ -389,30 +386,37 @@ public final class MainWindow implements Runnable, RipStatusHandler {
historyPanel.setPreferredSize(new Dimension(300, 250)); historyPanel.setPreferredSize(new Dimension(300, 250));
historyTableModel = new AbstractTableModel() { historyTableModel = new AbstractTableModel() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
public String getColumnName(int col) { public String getColumnName(int col) {
return HISTORY.getColumnName(col); return HISTORY.getColumnName(col);
} }
@Override @Override
public Class<?> getColumnClass(int c) { public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass(); return getValueAt(0, c).getClass();
} }
@Override @Override
public Object getValueAt(int row, int col) { public Object getValueAt(int row, int col) {
return HISTORY.getValueAt(row, col); return HISTORY.getValueAt(row, col);
} }
@Override @Override
public int getRowCount() { public int getRowCount() {
return HISTORY.toList().size(); return HISTORY.toList().size();
} }
@Override @Override
public int getColumnCount() { public int getColumnCount() {
return HISTORY.getColumnCount(); return HISTORY.getColumnCount();
} }
@Override @Override
public boolean isCellEditable(int row, int col) { public boolean isCellEditable(int row, int col) {
return (col == 0 || col == 4); return (col == 0 || col == 4);
} }
@Override @Override
public void setValueAt(Object value, int row, int col) { public void setValueAt(Object value, int row, int col) {
if (col == 4) { if (col == 4) {
@@ -440,9 +444,9 @@ public final class MainWindow implements Runnable, RipStatusHandler {
historyTable.getColumnModel().getColumn(i).setPreferredWidth(width); historyTable.getColumnModel().getColumn(i).setPreferredWidth(width);
} }
JScrollPane historyTableScrollPane = new JScrollPane(historyTable); JScrollPane historyTableScrollPane = new JScrollPane(historyTable);
historyButtonRemove = new JButton(rb.getString("remove")); historyButtonRemove = new JButton(Utils.getLocalizedString("remove"));
historyButtonClear = new JButton(rb.getString("clear")); historyButtonClear = new JButton(Utils.getLocalizedString("clear"));
historyButtonRerip = new JButton(rb.getString("re-rip.checked")); historyButtonRerip = new JButton(Utils.getLocalizedString("re-rip.checked"));
gbc.gridx = 0; gbc.gridx = 0;
// History List Panel // History List Panel
JPanel historyTablePanel = new JPanel(new GridBagLayout()); JPanel historyTablePanel = new JPanel(new GridBagLayout());
@@ -456,10 +460,14 @@ public final class MainWindow implements Runnable, RipStatusHandler {
JPanel historyButtonPanel = new JPanel(new GridBagLayout()); JPanel historyButtonPanel = new JPanel(new GridBagLayout());
historyButtonPanel.setPreferredSize(new Dimension(300, 10)); historyButtonPanel.setPreferredSize(new Dimension(300, 10));
historyButtonPanel.setBorder(emptyBorder); historyButtonPanel.setBorder(emptyBorder);
gbc.gridx = 0; historyButtonPanel.add(historyButtonRemove, gbc); gbc.gridx = 0;
gbc.gridx = 1; historyButtonPanel.add(historyButtonClear, gbc); historyButtonPanel.add(historyButtonRemove, gbc);
gbc.gridx = 2; historyButtonPanel.add(historyButtonRerip, gbc); gbc.gridx = 1;
gbc.gridy = 1; gbc.gridx = 0; historyButtonPanel.add(historyButtonClear, gbc);
gbc.gridx = 2;
historyButtonPanel.add(historyButtonRerip, gbc);
gbc.gridy = 1;
gbc.gridx = 0;
gbc.weighty = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
historyPanel.add(historyButtonPanel, gbc); historyPanel.add(historyButtonPanel, gbc);
@@ -468,17 +476,17 @@ public final class MainWindow implements Runnable, RipStatusHandler {
queuePanel.setBorder(emptyBorder); queuePanel.setBorder(emptyBorder);
queuePanel.setVisible(false); queuePanel.setVisible(false);
queuePanel.setPreferredSize(new Dimension(300, 250)); queuePanel.setPreferredSize(new Dimension(300, 250));
queueListModel = new DefaultListModel(); queueListModel = new DefaultListModel();
JList queueList = new JList(queueListModel); JList queueList = new JList(queueListModel);
queueList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); queueList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
queueList.addMouseListener(new QueueMenuMouseListener()); queueList.addMouseListener(queueMenuMouseListener = new QueueMenuMouseListener());
JScrollPane queueListScroll = new JScrollPane(queueList, JScrollPane queueListScroll = new JScrollPane(queueList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
for (String item : Utils.getConfigList("queue")) { for (String item : Utils.getConfigList("queue")) {
queueListModel.addElement(item); queueListModel.addElement(item);
} }
updateQueueLabel(); updateQueue();
gbc.gridx = 0; gbc.gridx = 0;
JPanel queueListPanel = new JPanel(new GridBagLayout()); JPanel queueListPanel = new JPanel(new GridBagLayout());
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
@@ -493,32 +501,42 @@ public final class MainWindow implements Runnable, RipStatusHandler {
configurationPanel.setBorder(emptyBorder); configurationPanel.setBorder(emptyBorder);
configurationPanel.setVisible(false); configurationPanel.setVisible(false);
// TODO Configuration components // TODO Configuration components
configUpdateButton = new JButton(rb.getString("check.for.updates")); configUpdateButton = new JButton(Utils.getLocalizedString("check.for.updates"));
configUpdateLabel = new JLabel( rb.getString("current.version") + ": " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT); configUpdateLabel = new JLabel(
configThreadsLabel = new JLabel(rb.getString("max.download.threads") + ":", JLabel.RIGHT); Utils.getLocalizedString("current.version") + ": " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT);
configTimeoutLabel = new JLabel(rb.getString("timeout.mill"), JLabel.RIGHT); configThreadsLabel = new JLabel(Utils.getLocalizedString("max.download.threads") + ":", JLabel.RIGHT);
configRetriesLabel = new JLabel(rb.getString("retry.download.count"), JLabel.RIGHT); configTimeoutLabel = new JLabel(Utils.getLocalizedString("timeout.mill"), JLabel.RIGHT);
configRetriesLabel = new JLabel(Utils.getLocalizedString("retry.download.count"), JLabel.RIGHT);
configThreadsText = new JTextField(Integer.toString(Utils.getConfigInteger("threads.size", 3))); configThreadsText = new JTextField(Integer.toString(Utils.getConfigInteger("threads.size", 3)));
configTimeoutText = new JTextField(Integer.toString(Utils.getConfigInteger("download.timeout", 60000))); configTimeoutText = new JTextField(Integer.toString(Utils.getConfigInteger("download.timeout", 60000)));
configRetriesText = new JTextField(Integer.toString(Utils.getConfigInteger("download.retries", 3))); configRetriesText = new JTextField(Integer.toString(Utils.getConfigInteger("download.retries", 3)));
configOverwriteCheckbox = addNewCheckbox(rb.getString("overwrite.existing.files"), "file.overwrite", false); configOverwriteCheckbox = addNewCheckbox(Utils.getLocalizedString("overwrite.existing.files"), "file.overwrite",
configAutoupdateCheckbox = addNewCheckbox(rb.getString("auto.update"), "auto.update", true); false);
configPlaySound = addNewCheckbox(rb.getString("sound.when.rip.completes"), "play.sound", false); configAutoupdateCheckbox = addNewCheckbox(Utils.getLocalizedString("auto.update"), "auto.update", true);
configShowPopup = addNewCheckbox(rb.getString("notification.when.rip.starts"), "download.show_popup", false); configPlaySound = addNewCheckbox(Utils.getLocalizedString("sound.when.rip.completes"), "play.sound", false);
configSaveOrderCheckbox = addNewCheckbox(rb.getString("preserve.order"), "download.save_order", true); configShowPopup = addNewCheckbox(Utils.getLocalizedString("notification.when.rip.starts"),
configSaveLogs = addNewCheckbox(rb.getString("save.logs"), "log.save", false); "download.show_popup", false);
configSaveURLsOnly = addNewCheckbox(rb.getString("save.urls.only"), "urls_only.save", false); configSaveOrderCheckbox = addNewCheckbox(Utils.getLocalizedString("preserve.order"), "download.save_order",
configSaveAlbumTitles = addNewCheckbox(rb.getString("save.album.titles"), "album_titles.save", true); true);
configClipboardAutorip = addNewCheckbox(rb.getString("autorip.from.clipboard"), "clipboard.autorip", false); configSaveLogs = addNewCheckbox(Utils.getLocalizedString("save.logs"), "log.save", false);
configSaveDescriptions = addNewCheckbox(rb.getString("save.descriptions"), "descriptions.save", true); configSaveURLsOnly = addNewCheckbox(Utils.getLocalizedString("save.urls.only"), "urls_only.save", false);
configPreferMp4 = addNewCheckbox(rb.getString("prefer.mp4.over.gif"),"prefer.mp4", false); configSaveAlbumTitles = addNewCheckbox(Utils.getLocalizedString("save.album.titles"), "album_titles.save",
configWindowPosition = addNewCheckbox(rb.getString("restore.window.position"), "window.position", true); true);
configURLHistoryCheckbox = addNewCheckbox(rb.getString("remember.url.history"), "remember.url_history", true); configClipboardAutorip = addNewCheckbox(Utils.getLocalizedString("autorip.from.clipboard"), "clipboard.autorip",
configUrlFileChooserButton = new JButton(rb.getString("download.url.list")); false);
configSaveDescriptions = addNewCheckbox(Utils.getLocalizedString("save.descriptions"), "descriptions.save",
true);
configPreferMp4 = addNewCheckbox(Utils.getLocalizedString("prefer.mp4.over.gif"), "prefer.mp4", false);
configWindowPosition = addNewCheckbox(Utils.getLocalizedString("restore.window.position"), "window.position",
true);
configURLHistoryCheckbox = addNewCheckbox(Utils.getLocalizedString("remember.url.history"),
"remember.url_history", true);
configUrlFileChooserButton = new JButton(Utils.getLocalizedString("download.url.list"));
configLogLevelCombobox = new JComboBox<>(new String[] {"Log level: Error", "Log level: Warn", "Log level: Info", "Log level: Debug"}); configLogLevelCombobox = new JComboBox<>(
configSelectLangComboBox = new JComboBox<>(supportedLanges); new String[] { "Log level: Error", "Log level: Warn", "Log level: Info", "Log level: Debug" });
configSelectLangComboBox.setSelectedItem(rb.getLocale().toString()); configSelectLangComboBox = new JComboBox<>(Utils.getSupportedLanguages());
configSelectLangComboBox.setSelectedItem(Utils.getSelectedLanguage());
configLogLevelCombobox.setSelectedItem(Utils.getConfigString("log.level", "Log level: Debug")); configLogLevelCombobox.setSelectedItem(Utils.getConfigString("log.level", "Log level: Debug"));
setLogLevel(configLogLevelCombobox.getSelectedItem().toString()); setLogLevel(configLogLevelCombobox.getSelectedItem().toString());
configSaveDirLabel = new JLabel(); configSaveDirLabel = new JLabel();
@@ -527,10 +545,11 @@ public final class MainWindow implements Runnable, RipStatusHandler {
configSaveDirLabel.setText(workingDir); configSaveDirLabel.setText(workingDir);
configSaveDirLabel.setForeground(Color.BLUE); configSaveDirLabel.setForeground(Color.BLUE);
configSaveDirLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); configSaveDirLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
} catch (Exception e) { } } catch (Exception e) {
}
configSaveDirLabel.setToolTipText(configSaveDirLabel.getText()); configSaveDirLabel.setToolTipText(configSaveDirLabel.getText());
configSaveDirLabel.setHorizontalAlignment(JLabel.RIGHT); configSaveDirLabel.setHorizontalAlignment(JLabel.RIGHT);
configSaveDirButton = new JButton(rb.getString("select.save.dir") + "..."); configSaveDirButton = new JButton(Utils.getLocalizedString("select.save.dir") + "...");
addItemToConfigGridBagConstraints(gbc, 0, configUpdateLabel, configUpdateButton); addItemToConfigGridBagConstraints(gbc, 0, configUpdateLabel, configUpdateButton);
addItemToConfigGridBagConstraints(gbc, 1, configAutoupdateCheckbox, configLogLevelCombobox); addItemToConfigGridBagConstraints(gbc, 1, configAutoupdateCheckbox, configLogLevelCombobox);
@@ -546,84 +565,112 @@ public final class MainWindow implements Runnable, RipStatusHandler {
addItemToConfigGridBagConstraints(gbc, 11, configSelectLangComboBox, configUrlFileChooserButton); addItemToConfigGridBagConstraints(gbc, 11, configSelectLangComboBox, configUrlFileChooserButton);
addItemToConfigGridBagConstraints(gbc, 12, configSaveDirLabel, configSaveDirButton); addItemToConfigGridBagConstraints(gbc, 12, configSaveDirLabel, configSaveDirButton);
emptyPanel = new JPanel(); emptyPanel = new JPanel();
emptyPanel.setPreferredSize(new Dimension(0, 0)); emptyPanel.setPreferredSize(new Dimension(0, 0));
emptyPanel.setSize(0, 0); emptyPanel.setSize(0, 0);
gbc.anchor = GridBagConstraints.PAGE_START; gbc.anchor = GridBagConstraints.PAGE_START;
gbc.gridy = 0; pane.add(ripPanel, gbc); gbc.gridy = 0;
gbc.gridy = 1; pane.add(statusPanel, gbc); pane.add(ripPanel, gbc);
gbc.gridy = 2; pane.add(progressPanel, gbc); gbc.gridy = 1;
gbc.gridy = 3; pane.add(optionsPanel, gbc); pane.add(statusPanel, gbc);
gbc.gridy = 2;
pane.add(progressPanel, gbc);
gbc.gridy = 3;
pane.add(optionsPanel, gbc);
gbc.weighty = 1; gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
gbc.gridy = 4; pane.add(logPanel, gbc); gbc.gridy = 4;
gbc.gridy = 5; pane.add(historyPanel, gbc); pane.add(logPanel, gbc);
gbc.gridy = 5; pane.add(queuePanel, gbc); gbc.gridy = 5;
gbc.gridy = 5; pane.add(configurationPanel, gbc); pane.add(historyPanel, gbc);
gbc.gridy = 5; pane.add(emptyPanel, gbc); gbc.gridy = 5;
pane.add(queuePanel, gbc);
gbc.gridy = 5;
pane.add(configurationPanel, gbc);
gbc.gridy = 5;
pane.add(emptyPanel, gbc);
gbc.weighty = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.fill = GridBagConstraints.HORIZONTAL;
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JLabel thing1ToAdd, JButton thing2ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JLabel thing1ToAdd,
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); JButton thing2ToAdd) {
gbc.gridx = 1; configurationPanel.add(thing2ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
gbc.gridx = 1;
configurationPanel.add(thing2ToAdd, gbc);
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JLabel thing1ToAdd, JTextField thing2ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JLabel thing1ToAdd,
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); JTextField thing2ToAdd) {
gbc.gridx = 1; configurationPanel.add(thing2ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
gbc.gridx = 1;
configurationPanel.add(thing2ToAdd, gbc);
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JCheckBox thing1ToAdd, JCheckBox thing2ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JCheckBox thing1ToAdd,
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); JCheckBox thing2ToAdd) {
gbc.gridx = 1; configurationPanel.add(thing2ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
gbc.gridx = 1;
configurationPanel.add(thing2ToAdd, gbc);
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JCheckBox thing1ToAdd, JComboBox thing2ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JCheckBox thing1ToAdd,
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); JComboBox thing2ToAdd) {
gbc.gridx = 1; configurationPanel.add(thing2ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
gbc.gridx = 1;
configurationPanel.add(thing2ToAdd, gbc);
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JComboBox thing1ToAdd, JButton thing2ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JComboBox thing1ToAdd,
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); JButton thing2ToAdd) {
gbc.gridx = 1; configurationPanel.add(thing2ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
gbc.gridx = 1;
configurationPanel.add(thing2ToAdd, gbc);
} }
private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JComboBox thing1ToAdd ) { private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JComboBox thing1ToAdd) {
gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); gbc.gridy = gbcYValue;
gbc.gridx = 0;
configurationPanel.add(thing1ToAdd, gbc);
} }
private void changeLocale() { private void changeLocale() {
statusLabel.setText(rb.getString("inactive")); statusLabel.setText(Utils.getLocalizedString("inactive"));
configUpdateButton.setText(rb.getString("check.for.updates")); configUpdateButton.setText(Utils.getLocalizedString("check.for.updates"));
configUpdateLabel.setText(rb.getString("current.version") + ": " + UpdateUtils.getThisJarVersion()); configUpdateLabel.setText(Utils.getLocalizedString("current.version") + ": " + UpdateUtils.getThisJarVersion());
configThreadsLabel.setText(rb.getString("max.download.threads")); configThreadsLabel.setText(Utils.getLocalizedString("max.download.threads"));
configTimeoutLabel.setText(rb.getString("timeout.mill")); configTimeoutLabel.setText(Utils.getLocalizedString("timeout.mill"));
configRetriesLabel.setText(rb.getString("retry.download.count")); configRetriesLabel.setText(Utils.getLocalizedString("retry.download.count"));
configOverwriteCheckbox.setText(rb.getString("overwrite.existing.files")); configOverwriteCheckbox.setText(Utils.getLocalizedString("overwrite.existing.files"));
configAutoupdateCheckbox.setText(rb.getString("auto.update")); configAutoupdateCheckbox.setText(Utils.getLocalizedString("auto.update"));
configPlaySound.setText(rb.getString("sound.when.rip.completes")); configPlaySound.setText(Utils.getLocalizedString("sound.when.rip.completes"));
configShowPopup.setText(rb.getString("notification.when.rip.starts")); configShowPopup.setText(Utils.getLocalizedString("notification.when.rip.starts"));
configSaveOrderCheckbox.setText(rb.getString("preserve.order")); configSaveOrderCheckbox.setText(Utils.getLocalizedString("preserve.order"));
configSaveLogs.setText(rb.getString("save.logs")); configSaveLogs.setText(Utils.getLocalizedString("save.logs"));
configSaveURLsOnly.setText(rb.getString("save.urls.only")); configSaveURLsOnly.setText(Utils.getLocalizedString("save.urls.only"));
configSaveAlbumTitles.setText(rb.getString("save.album.titles")); configSaveAlbumTitles.setText(Utils.getLocalizedString("save.album.titles"));
configClipboardAutorip.setText(rb.getString("autorip.from.clipboard")); configClipboardAutorip.setText(Utils.getLocalizedString("autorip.from.clipboard"));
configSaveDescriptions.setText(rb.getString("save.descriptions")); configSaveDescriptions.setText(Utils.getLocalizedString("save.descriptions"));
configUrlFileChooserButton.setText(rb.getString("download.url.list")); configUrlFileChooserButton.setText(Utils.getLocalizedString("download.url.list"));
configSaveDirButton.setText(rb.getString("select.save.dir") + "..."); configSaveDirButton.setText(Utils.getLocalizedString("select.save.dir") + "...");
configPreferMp4.setText(rb.getString("prefer.mp4.over.gif")); configPreferMp4.setText(Utils.getLocalizedString("prefer.mp4.over.gif"));
configWindowPosition.setText(rb.getString("restore.window.position")); configWindowPosition.setText(Utils.getLocalizedString("restore.window.position"));
configURLHistoryCheckbox.setText(rb.getString("remember.url.history")); configURLHistoryCheckbox.setText(Utils.getLocalizedString("remember.url.history"));
optionLog.setText(rb.getString("Log")); optionLog.setText(Utils.getLocalizedString("Log"));
optionHistory.setText(rb.getString("History")); optionHistory.setText(Utils.getLocalizedString("History"));
optionQueue.setText(rb.getString("Queue")); optionQueue.setText(Utils.getLocalizedString("queue"));
optionConfiguration.setText(rb.getString("Configuration")); optionConfiguration.setText(Utils.getLocalizedString("Configuration"));
} }
private void setupHandlers() { private void setupHandlers() {
@@ -634,14 +681,17 @@ public final class MainWindow implements Runnable, RipStatusHandler {
public void removeUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) {
update(); update();
} }
@Override @Override
public void insertUpdate(DocumentEvent e) { public void insertUpdate(DocumentEvent e) {
update(); update();
} }
@Override @Override
public void changedUpdate(DocumentEvent e) { public void changedUpdate(DocumentEvent e) {
update(); update();
} }
private void update() { private void update() {
try { try {
String urlText = ripTextfield.getText().trim(); String urlText = ripTextfield.getText().trim();
@@ -668,7 +718,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
statusProgress.setVisible(false); statusProgress.setVisible(false);
pack(); pack();
statusProgress.setValue(0); statusProgress.setValue(0);
status("Ripping interrupted"); status(Utils.getLocalizedString("ripping.interrupted"));
appendLog("Ripper interrupted", Color.RED); appendLog("Ripper interrupted", Color.RED);
} }
}); });
@@ -744,7 +794,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
try { try {
historyTableModel.fireTableDataChanged(); historyTableModel.fireTableDataChanged();
} catch (Exception e) { } } catch (Exception e) {
}
saveHistory(); saveHistory();
}); });
historyButtonClear.addActionListener(event -> { historyButtonClear.addActionListener(event -> {
@@ -778,8 +829,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
saveHistory(); saveHistory();
}); });
} } else {
else {
Utils.clearURLHistory(); Utils.clearURLHistory();
HISTORY.clear(); HISTORY.clear();
try { try {
@@ -793,9 +843,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
// Re-rip all history // Re-rip all history
historyButtonRerip.addActionListener(event -> { historyButtonRerip.addActionListener(event -> {
if (HISTORY.isEmpty()) { if (HISTORY.isEmpty()) {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null, Utils.getLocalizedString("history.load.none"), "RipMe Error",
"There are no history entries to re-rip. Rip some albums first",
"RipMe Error",
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
return; return;
} }
@@ -807,11 +855,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
} }
if (added == 0) { if (added == 0) {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null, Utils.getLocalizedString("history.load.none.checked"),
"No history entries have been 'Checked'\n" + "RipMe Error", JOptionPane.ERROR_MESSAGE);
"Check an entry by clicking the checkbox to the right of the URL or Right-click a URL to check/uncheck all items",
"RipMe Error",
JOptionPane.ERROR_MESSAGE);
} }
}); });
configUpdateButton.addActionListener(arg0 -> { configUpdateButton.addActionListener(arg0 -> {
@@ -824,7 +869,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
}); });
configSelectLangComboBox.addActionListener(arg0 -> { configSelectLangComboBox.addActionListener(arg0 -> {
String level = ((JComboBox) arg0.getSource()).getSelectedItem().toString(); String level = ((JComboBox) arg0.getSource()).getSelectedItem().toString();
rb = Utils.getResourceBundle(level); Utils.setLanguage(level);
changeLocale(); changeLocale();
}); });
configSaveDirLabel.addMouseListener(new MouseAdapter() { configSaveDirLabel.addMouseListener(new MouseAdapter() {
@@ -834,7 +879,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
Desktop desktop = Desktop.getDesktop(); Desktop desktop = Desktop.getDesktop();
try { try {
desktop.open(file); desktop.open(file);
} catch (Exception e1) { } } catch (Exception e1) {
}
} }
}); });
configSaveDirButton.addActionListener(arg0 -> { configSaveDirButton.addActionListener(arg0 -> {
@@ -882,11 +928,10 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
} }
} catch (IOException e) {
} catch(IOException e) { LOGGER.error("Error reading file " + e.getMessage());
LOGGER.error("Error reading file " + e.getMessage()); }
} });
});
addCheckboxListener(configSaveOrderCheckbox, "download.save_order"); addCheckboxListener(configSaveOrderCheckbox, "download.save_order");
addCheckboxListener(configOverwriteCheckbox, "file.overwrite"); addCheckboxListener(configOverwriteCheckbox, "file.overwrite");
addCheckboxListener(configSaveLogs, "log.save"); addCheckboxListener(configSaveLogs, "log.save");
@@ -896,7 +941,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
addCheckboxListener(configSaveDescriptions, "descriptions.save"); addCheckboxListener(configSaveDescriptions, "descriptions.save");
addCheckboxListener(configPreferMp4, "prefer.mp4"); addCheckboxListener(configPreferMp4, "prefer.mp4");
addCheckboxListener(configWindowPosition, "window.position"); addCheckboxListener(configWindowPosition, "window.position");
configClipboardAutorip.addActionListener(arg0 -> { configClipboardAutorip.addActionListener(arg0 -> {
Utils.setConfigBoolean("clipboard.autorip", configClipboardAutorip.isSelected()); Utils.setConfigBoolean("clipboard.autorip", configClipboardAutorip.isSelected());
ClipboardUtils.setClipboardAutoRip(configClipboardAutorip.isSelected()); ClipboardUtils.setClipboardAutoRip(configClipboardAutorip.isSelected());
@@ -907,15 +952,20 @@ public final class MainWindow implements Runnable, RipStatusHandler {
queueListModel.addListDataListener(new ListDataListener() { queueListModel.addListDataListener(new ListDataListener() {
@Override @Override
public void intervalAdded(ListDataEvent arg0) { public void intervalAdded(ListDataEvent arg0) {
updateQueueLabel(); updateQueue();
if (!isRipping) { if (!isRipping) {
ripNextAlbum(); ripNextAlbum();
} }
} }
@Override @Override
public void contentsChanged(ListDataEvent arg0) { } public void contentsChanged(ListDataEvent arg0) {
}
@Override @Override
public void intervalRemoved(ListDataEvent arg0) { } public void intervalRemoved(ListDataEvent arg0) {
}
}); });
} }
@@ -923,26 +973,26 @@ public final class MainWindow implements Runnable, RipStatusHandler {
Level newLevel = Level.ERROR; Level newLevel = Level.ERROR;
level = level.substring(level.lastIndexOf(' ') + 1); level = level.substring(level.lastIndexOf(' ') + 1);
switch (level) { switch (level) {
case "Debug": case "Debug":
newLevel = Level.DEBUG; newLevel = Level.DEBUG;
break; break;
case "Info": case "Info":
newLevel = Level.INFO; newLevel = Level.INFO;
break; break;
case "Warn": case "Warn":
newLevel = Level.WARN; newLevel = Level.WARN;
break; break;
case "Error": case "Error":
newLevel = Level.ERROR; newLevel = Level.ERROR;
break; break;
} }
Logger.getRootLogger().setLevel(newLevel); Logger.getRootLogger().setLevel(newLevel);
LOGGER.setLevel(newLevel); LOGGER.setLevel(newLevel);
ConsoleAppender ca = (ConsoleAppender)Logger.getRootLogger().getAppender("stdout"); ConsoleAppender ca = (ConsoleAppender) Logger.getRootLogger().getAppender("stdout");
if (ca != null) { if (ca != null) {
ca.setThreshold(newLevel); ca.setThreshold(newLevel);
} }
FileAppender fa = (FileAppender)Logger.getRootLogger().getAppender("FILE"); FileAppender fa = (FileAppender) Logger.getRootLogger().getAppender("FILE");
if (fa != null) { if (fa != null) {
fa.setThreshold(newLevel); fa.setThreshold(newLevel);
} }
@@ -951,23 +1001,32 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private void setupTrayIcon() { private void setupTrayIcon() {
mainFrame.addWindowListener(new WindowAdapter() { mainFrame.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowActivated(WindowEvent e) { trayMenuMain.setLabel("Hide"); } public void windowActivated(WindowEvent e) {
trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide"));
}
@Override @Override
public void windowDeactivated(WindowEvent e) { trayMenuMain.setLabel("Show"); } public void windowDeactivated(WindowEvent e) {
trayMenuMain.setLabel(Utils.getLocalizedString("tray.show"));
}
@Override @Override
public void windowDeiconified(WindowEvent e) { trayMenuMain.setLabel("Hide"); } public void windowDeiconified(WindowEvent e) {
trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide"));
}
@Override @Override
public void windowIconified(WindowEvent e) { trayMenuMain.setLabel("Show"); } public void windowIconified(WindowEvent e) {
trayMenuMain.setLabel(Utils.getLocalizedString("tray.show"));
}
}); });
PopupMenu trayMenu = new PopupMenu(); PopupMenu trayMenu = new PopupMenu();
trayMenuMain = new MenuItem("Hide"); trayMenuMain = new MenuItem(Utils.getLocalizedString("tray.hide"));
trayMenuMain.addActionListener(arg0 -> toggleTrayClick()); trayMenuMain.addActionListener(arg0 -> toggleTrayClick());
MenuItem trayMenuAbout = new MenuItem("About " + mainFrame.getTitle()); MenuItem trayMenuAbout = new MenuItem("About " + mainFrame.getTitle());
trayMenuAbout.addActionListener(arg0 -> { trayMenuAbout.addActionListener(arg0 -> {
StringBuilder about = new StringBuilder(); StringBuilder about = new StringBuilder();
about.append("<html><h1>") about.append("<html><h1>").append(mainFrame.getTitle()).append("</h1>");
.append(mainFrame.getTitle())
.append("</h1>");
about.append("Download albums from various websites:"); about.append("Download albums from various websites:");
try { try {
List<String> rippers = Utils.getListOfAlbumRippers(); List<String> rippers = Utils.getListOfAlbumRippers();
@@ -982,8 +1041,9 @@ public final class MainWindow implements Runnable, RipStatusHandler {
about.append("</li>"); about.append("</li>");
} }
about.append("</ul>"); about.append("</ul>");
} catch (Exception e) { } } catch (Exception e) {
about.append("<br>And download videos from video sites:"); }
about.append("<br>And download videos from video sites:");
try { try {
List<String> rippers = Utils.getListOfVideoRippers(); List<String> rippers = Utils.getListOfVideoRippers();
about.append("<ul>"); about.append("<ul>");
@@ -997,16 +1057,13 @@ public final class MainWindow implements Runnable, RipStatusHandler {
about.append("</li>"); about.append("</li>");
} }
about.append("</ul>"); about.append("</ul>");
} catch (Exception e) { } } catch (Exception e) {
}
about.append("Do you want to visit the project homepage on Github?"); about.append("Do you want to visit the project homepage on Github?");
about.append("</html>"); about.append("</html>");
int response = JOptionPane.showConfirmDialog(null, int response = JOptionPane.showConfirmDialog(null, about.toString(), mainFrame.getTitle(),
about.toString(), JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon(mainIcon));
mainFrame.getTitle(),
JOptionPane.YES_NO_OPTION,
JOptionPane.PLAIN_MESSAGE,
new ImageIcon(mainIcon));
if (response == JOptionPane.YES_OPTION) { if (response == JOptionPane.YES_OPTION) {
try { try {
Desktop.getDesktop().browse(URI.create("http://github.com/ripmeapp/ripme")); Desktop.getDesktop().browse(URI.create("http://github.com/ripmeapp/ripme"));
@@ -1015,9 +1072,9 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
} }
}); });
MenuItem trayMenuExit = new MenuItem("Exit"); MenuItem trayMenuExit = new MenuItem(Utils.getLocalizedString("tray.exit"));
trayMenuExit.addActionListener(arg0 -> System.exit(0)); trayMenuExit.addActionListener(arg0 -> System.exit(0));
trayMenuAutorip = new CheckboxMenuItem("Clipboard Autorip"); trayMenuAutorip = new CheckboxMenuItem(Utils.getLocalizedString("tray.autorip"));
trayMenuAutorip.addItemListener(arg0 -> { trayMenuAutorip.addItemListener(arg0 -> {
ClipboardUtils.setClipboardAutoRip(trayMenuAutorip.getState()); ClipboardUtils.setClipboardAutoRip(trayMenuAutorip.getState());
configClipboardAutorip.setSelected(trayMenuAutorip.getState()); configClipboardAutorip.setSelected(trayMenuAutorip.getState());
@@ -1047,29 +1104,28 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
}); });
} catch (IOException | AWTException e) { } catch (IOException | AWTException e) {
//TODO implement proper stack trace handling this is really just intented as a placeholder until you implement proper error handling // TODO implement proper stack trace handling this is really just intented as a
// placeholder until you implement proper error handling
e.printStackTrace(); e.printStackTrace();
} }
} }
private void toggleTrayClick() { private void toggleTrayClick() {
if (mainFrame.getExtendedState() == JFrame.ICONIFIED if (mainFrame.getExtendedState() == JFrame.ICONIFIED || !mainFrame.isActive() || !mainFrame.isVisible()) {
|| !mainFrame.isActive()
|| !mainFrame.isVisible()) {
mainFrame.setVisible(true); mainFrame.setVisible(true);
mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(true);
mainFrame.setAlwaysOnTop(false); mainFrame.setAlwaysOnTop(false);
trayMenuMain.setLabel("Hide"); trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide"));
} else { } else {
mainFrame.setVisible(false); mainFrame.setVisible(false);
trayMenuMain.setLabel("Show"); trayMenuMain.setLabel(Utils.getLocalizedString("tray.show"));
} }
} }
/** /**
* Write a line to the Log section of the GUI * Write a line to the Log section of the GUI
* *
* @param text the string to log * @param text the string to log
* @param color the color of the line * @param color the color of the line
*/ */
private void appendLog(final String text, final Color color) { private void appendLog(final String text, final Color color) {
@@ -1080,7 +1136,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
synchronized (this) { synchronized (this) {
sd.insertString(sd.getLength(), text + "\n", sas); sd.insertString(sd.getLength(), text + "\n", sas);
} }
} catch (BadLocationException e) { } } catch (BadLocationException e) {
}
logText.setCaretPosition(sd.getLength()); logText.setCaretPosition(sd.getLength());
} }
@@ -1088,7 +1145,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
/** /**
* Write a line to the GUI log and the CLI log * Write a line to the GUI log and the CLI log
* *
* @param line the string to log * @param line the string to log
* @param color the color of the line for the GUI log * @param color the color of the line for the GUI log
*/ */
public void displayAndLogError(String line, Color color) { public void displayAndLogError(String line, Color color) {
@@ -1101,25 +1158,22 @@ public final class MainWindow implements Runnable, RipStatusHandler {
HISTORY.clear(); HISTORY.clear();
if (historyFile.exists()) { if (historyFile.exists()) {
try { try {
LOGGER.info(rb.getString("loading.history.from") + " " + historyFile.getCanonicalPath()); LOGGER.info(Utils.getLocalizedString("loading.history.from") + " " + historyFile.getCanonicalPath());
HISTORY.fromFile(historyFile.getCanonicalPath()); HISTORY.fromFile(historyFile.getCanonicalPath());
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("Failed to load history from file " + historyFile, e); LOGGER.error("Failed to load history from file " + historyFile, e);
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
"RipMe failed to load the history file at " + historyFile.getAbsolutePath() + "\n\n" + String.format(Utils.getLocalizedString("history.load.failed.warning"), e.getMessage()),
"Error: " + e.getMessage() + "\n\n" + "RipMe - history load failure", JOptionPane.ERROR_MESSAGE);
"Closing RipMe will automatically overwrite the contents of this file,\n" +
"so you may want to back the file up before closing RipMe!",
"RipMe - history load failure",
JOptionPane.ERROR_MESSAGE);
} }
} else { } else {
LOGGER.info(rb.getString("loading.history.from.configuration")); LOGGER.info(Utils.getLocalizedString("loading.history.from.configuration"));
HISTORY.fromList(Utils.getConfigList("download.history")); HISTORY.fromList(Utils.getConfigList("download.history"));
if (HISTORY.toList().isEmpty()) { if (HISTORY.toList().isEmpty()) {
// Loaded from config, still no entries. // Loaded from config, still no entries.
// Guess rip history based on rip folder // Guess rip history based on rip folder
String[] dirs = Utils.getWorkingDirectory().list((dir, file) -> new File(dir.getAbsolutePath() + File.separator + file).isDirectory()); String[] dirs = Utils.getWorkingDirectory()
.list((dir, file) -> new File(dir.getAbsolutePath() + File.separator + file).isDirectory());
for (String dir : dirs) { for (String dir : dirs) {
String url = RipUtils.urlFromDirectoryName(dir); String url = RipUtils.urlFromDirectoryName(dir);
if (url != null) { if (url != null) {
@@ -1160,13 +1214,15 @@ public final class MainWindow implements Runnable, RipStatusHandler {
return; return;
} }
String nextAlbum = (String) queueListModel.remove(0); String nextAlbum = (String) queueListModel.remove(0);
updateQueueLabel();
updateQueue();
Thread t = ripAlbum(nextAlbum); Thread t = ripAlbum(nextAlbum);
if (t == null) { if (t == null) {
try { try {
Thread.sleep(500); Thread.sleep(500);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
LOGGER.error(rb.getString("interrupted.while.waiting.to.rip.next.album"), ie); LOGGER.error(Utils.getLocalizedString("interrupted.while.waiting.to.rip.next.album"), ie);
} }
ripNextAlbum(); ripNextAlbum();
} else { } else {
@@ -1175,7 +1231,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
} }
private Thread ripAlbum(String urlString) { private Thread ripAlbum(String urlString) {
//shutdownCleanup(); // shutdownCleanup();
if (!logPanel.isVisible()) { if (!logPanel.isVisible()) {
optionLog.doClick(); optionLog.doClick();
} }
@@ -1214,11 +1270,11 @@ public final class MainWindow implements Runnable, RipStatusHandler {
status("Starting rip..."); status("Starting rip...");
ripper.setObserver(this); ripper.setObserver(this);
Thread t = new Thread(ripper); Thread t = new Thread(ripper);
if (configShowPopup.isSelected() && if (configShowPopup.isSelected() && (!mainFrame.isVisible() || !mainFrame.isActive())) {
(!mainFrame.isVisible() || !mainFrame.isActive())) {
mainFrame.toFront(); mainFrame.toFront();
mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(true);
trayIcon.displayMessage(mainFrame.getTitle(), "Started ripping " + ripper.getURL().toExternalForm(), MessageType.INFO); trayIcon.displayMessage(mainFrame.getTitle(), "Started ripping " + ripper.getURL().toExternalForm(),
MessageType.INFO);
mainFrame.setAlwaysOnTop(false); mainFrame.setAlwaysOnTop(false);
} }
return t; return t;
@@ -1262,7 +1318,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
String rangeToParse = url.substring(url.indexOf("{") + 1, url.indexOf("}")); String rangeToParse = url.substring(url.indexOf("{") + 1, url.indexOf("}"));
int rangeStart = Integer.parseInt(rangeToParse.split("-")[0]); int rangeStart = Integer.parseInt(rangeToParse.split("-")[0]);
int rangeEnd = Integer.parseInt(rangeToParse.split("-")[1]); int rangeEnd = Integer.parseInt(rangeToParse.split("-")[1]);
for (int i = rangeStart; i < rangeEnd +1; i++) { for (int i = rangeStart; i < rangeEnd + 1; i++) {
String realURL = url.replaceAll("\\{\\S*\\}", Integer.toString(i)); String realURL = url.replaceAll("\\{\\S*\\}", Integer.toString(i));
if (canRip(realURL)) { if (canRip(realURL)) {
queueListModel.add(queueListModel.size(), realURL); queueListModel.add(queueListModel.size(), realURL);
@@ -1307,9 +1363,9 @@ public final class MainWindow implements Runnable, RipStatusHandler {
int completedPercent = evt.ripper.getCompletionPercentage(); int completedPercent = evt.ripper.getCompletionPercentage();
statusProgress.setValue(completedPercent); statusProgress.setValue(completedPercent);
statusProgress.setVisible(true); statusProgress.setVisible(true);
status( evt.ripper.getStatusText() ); status(evt.ripper.getStatusText());
switch(msg.getStatus()) { switch (msg.getStatus()) {
case LOADING_RESOURCE: case LOADING_RESOURCE:
case DOWNLOAD_STARTED: case DOWNLOAD_STARTED:
if (LOGGER.isEnabledFor(Level.INFO)) { if (LOGGER.isEnabledFor(Level.INFO)) {
@@ -1365,7 +1421,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
entry.count = rsc.count; entry.count = rsc.count;
try { try {
entry.title = ripper.getAlbumTitle(ripper.getURL()); entry.title = ripper.getAlbumTitle(ripper.getURL());
} catch (MalformedURLException e) { } } catch (MalformedURLException e) {
}
HISTORY.add(entry); HISTORY.add(entry);
historyTableModel.fireTableDataChanged(); historyTableModel.fireTableDataChanged();
} }
@@ -1379,15 +1436,15 @@ public final class MainWindow implements Runnable, RipStatusHandler {
openButton.setVisible(true); openButton.setVisible(true);
File f = rsc.dir; File f = rsc.dir;
String prettyFile = Utils.shortenPath(f); String prettyFile = Utils.shortenPath(f);
openButton.setText("Open " + prettyFile); openButton.setText(Utils.getLocalizedString("open") + prettyFile);
mainFrame.setTitle("RipMe v" + UpdateUtils.getThisJarVersion()); mainFrame.setTitle("RipMe v" + UpdateUtils.getThisJarVersion());
try { try {
Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png")); Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png"));
openButton.setIcon(new ImageIcon(folderIcon)); openButton.setIcon(new ImageIcon(folderIcon));
} catch (Exception e) { } } catch (Exception e) {
/* content key }
* %path% the path to the album folder /*
* %url% is the album url * content key %path% the path to the album folder %url% is the album url
*/ */
if (Utils.getConfigBoolean("enable.finish.command", false)) { if (Utils.getConfigBoolean("enable.finish.command", false)) {
try { try {
@@ -1395,13 +1452,12 @@ public final class MainWindow implements Runnable, RipStatusHandler {
commandToRun = commandToRun.replaceAll("%url%", url); commandToRun = commandToRun.replaceAll("%url%", url);
commandToRun = commandToRun.replaceAll("%path%", f.getAbsolutePath()); commandToRun = commandToRun.replaceAll("%path%", f.getAbsolutePath());
LOGGER.info("RUnning command " + commandToRun); LOGGER.info("RUnning command " + commandToRun);
// code from: https://stackoverflow.com/questions/5711084/java-runtime-getruntime-getting-output-from-executing-a-command-line-program // code from:
// https://stackoverflow.com/questions/5711084/java-runtime-getruntime-getting-output-from-executing-a-command-line-program
Process proc = Runtime.getRuntime().exec(commandToRun); Process proc = Runtime.getRuntime().exec(commandToRun);
BufferedReader stdInput = new BufferedReader(new BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
InputStreamReader(proc.getErrorStream()));
// read the output from the command // read the output from the command
LOGGER.info("Command output:\n"); LOGGER.info("Command output:\n");
@@ -1472,9 +1528,11 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private static boolean hasWindowPositionBug() { private static boolean hasWindowPositionBug() {
String osName = System.getProperty("os.name"); String osName = System.getProperty("os.name");
// Java on Windows has a bug where if we try to manually set the position of the Window, // Java on Windows has a bug where if we try to manually set the position of the
// Window,
// javaw.exe will not close itself down when the application is closed. // javaw.exe will not close itself down when the application is closed.
// Therefore, even if isWindowPositioningEnabled, if we are on Windows, we ignore it. // Therefore, even if isWindowPositioningEnabled, if we are on Windows, we
// ignore it.
return osName == null || osName.startsWith("Windows"); return osName == null || osName.startsWith("Windows");
} }
@@ -1500,8 +1558,8 @@ public final class MainWindow implements Runnable, RipStatusHandler {
return; return;
} }
} }
int x = (int)point.getX(); int x = (int) point.getX();
int y = (int)point.getY(); int y = (int) point.getY();
int w = frame.getWidth(); int w = frame.getWidth();
int h = frame.getHeight(); int h = frame.getHeight();
Utils.setConfigInteger("window.x", x); Utils.setConfigInteger("window.x", x);

View File

@@ -2,18 +2,27 @@ package com.rarchives.ripme.utils;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -21,6 +30,9 @@ import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip; import javax.sound.sampled.Clip;
@@ -40,6 +52,8 @@ import org.apache.log4j.PropertyConfigurator;
*/ */
public class Utils { public class Utils {
private static final Pattern pattern = Pattern.compile("LabelsBundle_(?<lang>[A-Za-z_]+).properties");
private static final String DEFAULT_LANG = "en_US";
private static final String RIP_DIRECTORY = "rips"; private static final String RIP_DIRECTORY = "rips";
private static final String CONFIG_FILE = "rip.properties"; private static final String CONFIG_FILE = "rip.properties";
private static final String OS = System.getProperty("os.name").toLowerCase(); private static final String OS = System.getProperty("os.name").toLowerCase();
@@ -50,6 +64,8 @@ public class Utils {
private static HashMap<String, HashMap<String, String>> cookieCache; private static HashMap<String, HashMap<String, String>> cookieCache;
private static HashMap<ByteBuffer, String> magicHash = new HashMap<>(); private static HashMap<ByteBuffer, String> magicHash = new HashMap<>();
private static ResourceBundle resourceBundle = null;
static { static {
cookieCache = new HashMap<>(); cookieCache = new HashMap<>();
@@ -83,6 +99,8 @@ public class Utils {
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("[!] Failed to load properties file from " + CONFIG_FILE, e); LOGGER.error("[!] Failed to load properties file from " + CONFIG_FILE, e);
} }
resourceBundle = getResourceBundle(null);
} }
/** /**
@@ -737,6 +755,52 @@ public class Utils {
} }
} }
public static void setLanguage(String langSelect) {
resourceBundle = getResourceBundle(langSelect);
}
public static String getSelectedLanguage() {
return resourceBundle.getLocale().toString();
}
// All the langs ripme has been translated into
public static String[] getSupportedLanguages() {
ArrayList<Path> filesList = new ArrayList<>();
try {
URI uri = Utils.class.getResource("/rip.properties").toURI();
Path myPath;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
myPath = fileSystem.getPath("/");
} else {
myPath = Paths.get(uri).getParent();
}
Files.walk(myPath, 1).filter(p -> p.toString().contains("LabelsBundle_")).distinct()
.forEach(filesList::add);
String[] langs = new String[filesList.size()];
for (int i = 0; i < filesList.size(); i++) {
Matcher matcher = pattern.matcher(filesList.get(i).toString());
if (matcher.find())
langs[i] = matcher.group("lang");
}
return langs;
} catch (Exception e) {
e.printStackTrace();
// On error return default language
return new String[] { DEFAULT_LANG };
}
}
public static String getLocalizedString(String key) {
LOGGER.debug(String.format("Getting key %s in %s value %s", key, getSelectedLanguage(),
resourceBundle.getString(key)));
return resourceBundle.getString(key);
}
/** /**
* Formats and reuturns the status text for rippers using the byte progress bar * Formats and reuturns the status text for rippers using the byte progress bar
* *

View File

@@ -2,11 +2,11 @@ Log = Log
History = History History = History
created = created created = created
modified = modified modified = modified
Queue = Queue queue = Queue
Configuration = Configuration Configuration = Configuration
open = Open
# Keys for the Configuration menu # Keys for the Configuration menu
current.version = Current version current.version = Current version
check.for.updates = Check for updates check.for.updates = Check for updates
auto.update = Auto-update? auto.update = Auto-update?
@@ -27,19 +27,37 @@ restore.window.position = Restore window position
remember.url.history = Remember URL history remember.url.history = Remember URL history
loading.history.from = Loading history from loading.history.from = Loading history from
# Misc UI keys # Queue keys
queue.remove.all = Remove All
queue.validation = Are you sure you want to remove all elements from the queue?
queue.remove.selected = Remove Selected
loading.history.from.configuration = Loading history from configuration # History
interrupted.while.waiting.to.rip.next.album = Interrupted while waiting to rip next album
inactive = Inactive
re-rip.checked = Re-rip Checked re-rip.checked = Re-rip Checked
remove = Remove remove = Remove
clear = Clear clear = Clear
history.check.all = Check All
history.check.none = Check None
history.check.selected = Check Selected
history.uncheck.selected = Uncheck Selected
history.load.failed.warning = RipMe failed to load the history file at historyFile.getAbsolutePath() \n\nError: %s\n\nClosing RipMe will automatically overwrite the contents of this file,\nso you may want to back the file up before closing RipMe!
history.load.none = There are no history entries to re-rip. Rip some albums first
history.load.none.checked = No history entries have been 'Checked' Check an entry by clicking the checkbox to the right of the URL or Right-click a URL to check/uncheck all items
# TrayIcon
tray.show = Show
tray.hide = Hide
tray.autorip = Clipboard Autorip
tray.exit = Exit
# Misc UI keys
loading.history.from.configuration = Loading history from configuration
interrupted.while.waiting.to.rip.next.album = Interrupted while waiting to rip next album
inactive = Inactive
download.url.list = Download url list download.url.list = Download url list
select.save.dir = Select Save Directory select.save.dir = Select Save Directory
# Keys for the logs generated by DownloadFileThread # Keys for the logs generated by DownloadFileThread
nonretriable.status.code = Non-retriable status code nonretriable.status.code = Non-retriable status code
retriable.status.code = Retriable status code retriable.status.code = Retriable status code
server.doesnt.support.resuming.downloads = Server doesn't support resuming downloads server.doesnt.support.resuming.downloads = Server doesn't support resuming downloads

View File

@@ -2,7 +2,7 @@ Log = \u0645\u0644\u0641 \u0627\u0644\u062A\u062A\u0628\u0639
History = \u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645 History = \u0630\u0627\u0643\u0631\u0629 \u0627\u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645
created = \u0627\u0644\u0627\u0646\u0634\u0627\u0621 created = \u0627\u0644\u0627\u0646\u0634\u0627\u0621
modified = \u062A\u0645 \u0627\u0644\u062A\u0639\u062F\u064A\u0644 modified = \u062A\u0645 \u0627\u0644\u062A\u0639\u062F\u064A\u0644
Queue = \u0637\u0627\u0628\u0648\u0631 queue = \u0637\u0627\u0628\u0648\u0631
Configuration = \u062A\u0631\u062A\u064A\u0628 Configuration = \u062A\u0631\u062A\u064A\u0628
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -1,8 +1,8 @@
Log = Log Log = Log
History = Verlauf History = Verlauf
created = erstellt created = erstellt
modified = geändert modified = geändert
Queue = Queue queue = Queue
Configuration = Konfiguration Configuration = Konfiguration
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -1,57 +1 @@
Log = Log # This need to be empty since EN is the default language in the bundles
History = History
created = created
modified = modified
Queue = Queue
Configuration = Configuration
# Keys for the Configuration menu
current.version = Current version
check.for.updates = Check for updates
auto.update = Auto-update?
max.download.threads = Maximum download threads:
timeout.mill = Timeout (in milliseconds):
retry.download.count = Retry download count
overwrite.existing.files = Overwrite existing files?
sound.when.rip.completes = Sound when rip completes
preserve.order = Preserve order
save.logs = Save logs
notification.when.rip.starts = Notification when rip starts
save.urls.only = Save URLs only
save.album.titles = Save album titles
autorip.from.clipboard = Autorip from Clipboard
save.descriptions = Save descriptions
prefer.mp4.over.gif = Prefer MP4 over GIF
restore.window.position = Restore window position
remember.url.history = Remember URL history
loading.history.from = Loading history from
# Misc UI keys
loading.history.from.configuration = Loading history from configuration
interrupted.while.waiting.to.rip.next.album = Interrupted while waiting to rip next album
inactive = Inactive
re-rip.checked = Re-rip Checked
remove = Remove
clear = Clear
download.url.list = Download url list
select.save.dir = Select Save Directory
# Keys for the logs generated by DownloadFileThread
nonretriable.status.code = Non-retriable status code
retriable.status.code = Retriable status code
server.doesnt.support.resuming.downloads = Server doesn't support resuming downloads
# A "magic number" can also be called a file signature
was.unable.to.get.content.type.using.magic.number = Was unable to get content type using magic number
magic.number.was = Magic number was
deleting.existing.file = Deleting existing file
request.properties = Request properties
download.interrupted = Download interrupted
exceeded.maximum.retries = Exceeded maximum retries
http.status.exception = HTTP status exception
exception.while.downloading.file = Exception while downloading file
failed.to.download = Failed to download
skipping = Skipping
file.already.exists = file already exists

View File

@@ -2,7 +2,7 @@ Log = Log
History = Historia History = Historia
created = creado created = creado
modified = modificado modified = modificado
Queue = Cola queue = Cola
Configuration = Configuracion Configuration = Configuracion
# Keys for the Configuration menu # Keys for the Configuration menu
@@ -27,6 +27,11 @@ restore.window.position = Restaurar posicion de ventana
remember.url.history = Recordar historia URL remember.url.history = Recordar historia URL
loading.history.from = Cargando historia desde loading.history.from = Cargando historia desde
# Queue keys
queue.remove.all = Eliminar todos los elementos
queue.validation = ¿Esta seguro que desea eliminar todos los elementos de la lista?
queue.remove.selected = Eliminar elementos seleccionados
# Misc UI keys # Misc UI keys
loading.history.from.configuration = Cargando historia desde la configuracion loading.history.from.configuration = Cargando historia desde la configuracion

View File

@@ -2,7 +2,7 @@ Log = Logi
History = Historia History = Historia
created = luotu created = luotu
modified = muokattu modified = muokattu
Queue = Jono queue = Jono
Configuration = Asetukset Configuration = Asetukset
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Journal
History = Historique History = Historique
created = créé le created = créé le
modified = modifié le modified = modifié le
Queue = File d'attente queue = File d'attente
Configuration = Configuration Configuration = Configuration
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Log
History = Riwayat History = Riwayat
created = dibuat pada created = dibuat pada
modified = diubah pada modified = diubah pada
Queue = Antrian queue = Antrian
Configuration = Pengaturan Configuration = Pengaturan
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Log
History = Cronologia History = Cronologia
created = creato created = creato
modified = modificato modified = modificato
Queue = Coda queue = Coda
Configuration = Configurazione Configuration = Configurazione
# Keys for the Configuration menu # Keys for the Configuration menu
@@ -44,14 +44,14 @@ nonretriable.status.code = Codice di stato irreversibile
retriable.status.code = Codice di stato reversibile retriable.status.code = Codice di stato reversibile
server.doesnt.support.resuming.downloads = Il server non supporta la ripresa dei download server.doesnt.support.resuming.downloads = Il server non supporta la ripresa dei download
# A "magic number" can also be called a file signature # A "magic number" can also be called a file signature
was.unable.to.get.content.type.using.magic.number = Non <20> stato possibile ottenere il tipo del contenuto usando magic number was.unable.to.get.content.type.using.magic.number = Non <20> stato possibile ottenere il tipo del contenuto usando magic number
magic.number.was = Magic number era magic.number.was = Magic number era
deleting.existing.file = Cancellazione file esistente deleting.existing.file = Cancellazione file esistente
request.properties = Richiesta propriet<65> request.properties = Richiesta propriet<65>
download.interrupted = Download interrotto download.interrupted = Download interrotto
exceeded.maximum.retries = Superato il numero massimo di tentativi exceeded.maximum.retries = Superato il numero massimo di tentativi
http.status.exception = Eccezione stato HTTP http.status.exception = Eccezione stato HTTP
exception.while.downloading.file = Eccezione durante il download del file exception.while.downloading.file = Eccezione durante il download del file
failed.to.download = Download non riuscito failed.to.download = Download non riuscito
skipping = Saltare skipping = Saltare
file.already.exists = il file esiste gi<67> file.already.exists = il file esiste gi<67>

View File

@@ -2,7 +2,7 @@ Log = \uB85C\uADF8
History = \uD788\uC2A4\uD1A0\uB9AC History = \uD788\uC2A4\uD1A0\uB9AC
created = \uC0DD\uC0B0\uB428 created = \uC0DD\uC0B0\uB428
modified = \uC218\uC815\uB428 modified = \uC218\uC815\uB428
Queue = \uB300\uAE30\uC5F4 queue = \uB300\uAE30\uC5F4
Configuration = \uAD6C\uC131 Configuration = \uAD6C\uC131
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Logboek
History = Geschiedenis History = Geschiedenis
created = gemaakt created = gemaakt
modified = aangepast modified = aangepast
Queue = Wachtrij queue = Wachtrij
Configuration = Configuratie Configuration = Configuratie
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -1,8 +1,8 @@
Log = Logi Log = Logi
History = Historia History = Historia
created = Stworzono created = Stworzono
modified = Zmodyfikowano modified = Zmodyfikowano
Queue = Kolejka queue = Kolejka
Configuration = Konfiguracja Configuration = Konfiguracja
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Loki
History = Historriijja History = Historriijja
created = luatu created = luatu
modified = muakat modified = muakat
Queue = Jono queue = Jono
Configuration = Assetuksse Configuration = Assetuksse
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Registro
History = Histórico History = Histórico
created = criado created = criado
modified = modificado modified = modificado
Queue = Fila queue = Fila
Configuration = Configuração Configuration = Configuração
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -2,7 +2,7 @@ Log = Registo
History = Histórico History = Histórico
created = criado created = criado
modified = modificado modified = modificado
Queue = Fila queue = Fila
Configuration = Configuração Configuration = Configuração
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -1,8 +1,8 @@
Log = Лог Log = Лог
History = История History = История
created = создано created = создано
modified = изменено modified = изменено
Queue = Очередь queue = Очередь
Configuration = Настройки Configuration = Настройки
# Keys for the Configuration menu # Keys for the Configuration menu

View File

@@ -0,0 +1,61 @@
package com.rarchives.ripme.tst.ui;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.ResourceBundle;
import java.util.Set;
import com.rarchives.ripme.utils.Utils;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class LabelsBundlesTest {
private Logger logger = Logger.getLogger(Utils.class);
private static final String DEFAULT_LANG = "en_US";
@Test
void testKeyCount() {
ResourceBundle defaultBundle = Utils.getResourceBundle(null);
HashMap<String, ArrayList<String>> dictionary = new HashMap<>();
for (String lang : Utils.getSupportedLanguages()) {
ResourceBundle.clearCache();
if (lang.equals(DEFAULT_LANG))
continue;
ResourceBundle selectedLang = Utils.getResourceBundle(lang);
for (final Enumeration<String> keys = defaultBundle.getKeys(); keys.hasMoreElements();) {
String element = keys.nextElement();
if (selectedLang.containsKey(element)
&& !selectedLang.getString(element).equals(defaultBundle.getString(element))) {
if (dictionary.get(lang) == null)
dictionary.put(lang, new ArrayList<>());
dictionary.get(lang).add(element);
}
}
}
dictionary.keySet().forEach(d -> {
logger.warn(String.format("Keys missing in %s", d));
dictionary.get(d).forEach(v -> logger.warn(v));
logger.warn("\n");
});
}
@Test
void testKeyName() {
ResourceBundle defaultBundle = Utils.getResourceBundle(null);
Set<String> defaultSet = defaultBundle.keySet();
for (String lang : Utils.getSupportedLanguages()) {
if (lang.equals(DEFAULT_LANG))
continue;
for (String key : Utils.getResourceBundle(lang).keySet()) {
assertTrue(defaultSet.contains(key),
String.format("The key %s of %s is not in the default bundle", key, lang));
}
}
}
}

16
workspace.code-workspace Normal file
View File

@@ -0,0 +1,16 @@
{
"folders": [
{
"path": "E:\\Downloads\\_Isaaku\\dev"
}
],
"settings": {
"files.exclude": {
"**/.classpath": false,
"**/.project": true,
"**/.settings": true,
"**/.factorypath": true
},
"java.configuration.updateBuildConfiguration": "automatic"
}
}