diff --git a/pom.xml b/pom.xml
index 0796e60f..317b816e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.rarchives.ripme
ripme
jar
- 1.7.44
+ 1.7.45
ripme
http://rip.rarchives.com
diff --git a/ripme.json b/ripme.json
index 757058ae..73b9b240 100644
--- a/ripme.json
+++ b/ripme.json
@@ -1,6 +1,7 @@
{
- "latestVersion": "1.7.44",
+ "latestVersion": "1.7.45",
"changeList": [
+ "1.7.45: Fixed hentai2read ripper; ImageBam album fixed; Added various translations; TsuminoRipper no longer requires album name to download",
"1.7.44: Fixed instagram ripper regex",
"1.7.43: Fixed queryId regex in instagram ripper",
"1.7.42: Added user support to SmuttyRipper; Removed vine ripper; Fixed NudeGalsRipper; addURLToDownload improvments; Fixed Instagram ripper",
diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/DeviantartRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/DeviantartRipper.java
index 8ecb8086..9ab23ec8 100644
--- a/src/main/java/com/rarchives/ripme/ripper/rippers/DeviantartRipper.java
+++ b/src/main/java/com/rarchives/ripme/ripper/rippers/DeviantartRipper.java
@@ -121,7 +121,7 @@ public class DeviantartRipper extends AbstractHTMLRipper {
String username = Utils.getConfigString("deviantart.username", new String(Base64.decode("Z3JhYnB5")));
String password = Utils.getConfigString("deviantart.password", new String(Base64.decode("ZmFrZXJz")));
- if(username == null || password == null) {
+ if (username == null || password == null) {
logger.debug("No DeviantArt login provided.");
cookies.put("agegate_state","1"); // Bypasses the age gate
} else {
diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/Hentai2readRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/Hentai2readRipper.java
index 405d0563..a87575bd 100644
--- a/src/main/java/com/rarchives/ripme/ripper/rippers/Hentai2readRipper.java
+++ b/src/main/java/com/rarchives/ripme/ripper/rippers/Hentai2readRipper.java
@@ -44,20 +44,15 @@ public class Hentai2readRipper extends AbstractHTMLRipper {
@Override
public Document getFirstPage() throws IOException {
- Document tempDoc;
- // get the first page of the comic
- if (url.toExternalForm().substring(url.toExternalForm().length() - 1).equals("/")) {
- tempDoc = Http.url(url + "1").get();
- } else {
- tempDoc = Http.url(url + "/1").get();
+ try {
+ Document tempDoc;
+ tempDoc = Http.url(url).get();
+ // Get the thumbnail page so we can rip all images without loading every page in the comic
+ String thumbnailLink = tempDoc.select("a[data-original-title=Thumbnails").attr("href");
+ return Http.url(thumbnailLink).get();
+ } catch (IOException e) {
+ throw new IOException("Unable to get first page");
}
- for (Element el : tempDoc.select("ul.nav > li > a")) {
- if (el.attr("href").startsWith("https://hentai2read.com/thumbnails/")) {
- // Get the page with the thumbnails
- return Http.url(el.attr("href")).get();
- }
- }
- throw new IOException("Unable to get first page");
}
@Override
diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/ImagebamRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/ImagebamRipper.java
index 323ad1de..b33f5624 100644
--- a/src/main/java/com/rarchives/ripme/ripper/rippers/ImagebamRipper.java
+++ b/src/main/java/com/rarchives/ripme/ripper/rippers/ImagebamRipper.java
@@ -1,5 +1,9 @@
package com.rarchives.ripme.ripper.rippers;
+import com.rarchives.ripme.ripper.AbstractHTMLRipper;
+import com.rarchives.ripme.ripper.DownloadThreadPool;
+import com.rarchives.ripme.utils.Http;
+import com.rarchives.ripme.utils.Utils;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -7,16 +11,10 @@ import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
-import com.rarchives.ripme.ripper.AbstractHTMLRipper;
-import com.rarchives.ripme.ripper.DownloadThreadPool;
-import com.rarchives.ripme.utils.Http;
-import com.rarchives.ripme.utils.Utils;
-
public class ImagebamRipper extends AbstractHTMLRipper {
// Current HTML document
@@ -71,7 +69,7 @@ public class ImagebamRipper extends AbstractHTMLRipper {
public Document getNextPage(Document doc) throws IOException {
// Find next page
Elements hrefs = doc.select("a.pagination_current + a.pagination_link");
- if (hrefs.size() == 0) {
+ if (hrefs.isEmpty()) {
throw new IOException("No more pages");
}
String nextUrl = "http://www.imagebam.com" + hrefs.first().attr("href");
@@ -121,8 +119,8 @@ public class ImagebamRipper extends AbstractHTMLRipper {
* Handles case when site has IP-banned the user.
*/
private class ImagebamImageThread extends Thread {
- private URL url;
- private int index;
+ private URL url; //link to "image page"
+ private int index; //index in album
ImagebamImageThread(URL url, int index) {
super();
@@ -134,28 +132,43 @@ public class ImagebamRipper extends AbstractHTMLRipper {
public void run() {
fetchImage();
}
-
+
+ /**
+ * Rips useful image from "image page"
+ */
private void fetchImage() {
try {
Document doc = Http.url(url).get();
// Find image
- Elements images = doc.select(".image-container img");
- if (images.size() == 0) {
+ Elements metaTags = doc.getElementsByTag("meta");
+
+ String imgsrc = "";//initialize, so no NullPointerExceptions should ever happen.
+
+ for (Element metaTag: metaTags) {
+ //the direct link to the image seems to always be linked in the part of the html.
+ if (metaTag.attr("property").equals("og:image")) {
+ imgsrc = metaTag.attr("content");
+ logger.info("Found URL " + imgsrc);
+ break;//only one (useful) image possible for an "image page".
+ }
+ }
+
+ //for debug, or something goes wrong.
+ if (imgsrc.isEmpty()) {
logger.warn("Image not found at " + this.url);
return;
}
- Element image = images.first();
- String imgsrc = image.attr("src");
- logger.info("Found URL " + imgsrc);
+
// Provide prefix and let the AbstractRipper "guess" the filename
String prefix = "";
if (Utils.getConfigBoolean("download.save_order", true)) {
prefix = String.format("%03d_", index);
}
+
addURLToDownload(new URL(imgsrc), prefix);
} catch (IOException e) {
logger.error("[!] Exception while loading/parsing " + this.url, e);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/TsuminoRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/TsuminoRipper.java
index 7d35fc1d..70c023d3 100644
--- a/src/main/java/com/rarchives/ripme/ripper/rippers/TsuminoRipper.java
+++ b/src/main/java/com/rarchives/ripme/ripper/rippers/TsuminoRipper.java
@@ -59,11 +59,16 @@ public class TsuminoRipper extends AbstractHTMLRipper {
@Override
public String getGID(URL url) throws MalformedURLException {
- Pattern p = Pattern.compile("https?://www.tsumino.com/Book/Info/([0-9]+)/([a-zA-Z0-9_-]*)");
+ Pattern p = Pattern.compile("https?://www.tsumino.com/Book/Info/([0-9]+)/([a-zA-Z0-9_-]*)/?");
Matcher m = p.matcher(url.toExternalForm());
if (m.matches()) {
return m.group(1) + "_" + m.group(2);
}
+ p = Pattern.compile("https?://www.tsumino.com/Book/Info/([0-9]+)/?");
+ m = p.matcher(url.toExternalForm());
+ if (m.matches()) {
+ return m.group(1);
+ }
throw new MalformedURLException("Expected tsumino URL format: " +
"tsumino.com/Book/Info/ID/TITLE - got " + url + " instead");
}
diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java
index 016d25f3..95961f44 100644
--- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java
+++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java
@@ -16,9 +16,7 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
+import java.util.*;
import java.util.List;
import javax.imageio.ImageIO;
@@ -138,6 +136,17 @@ public final class MainWindow implements Runnable, RipStatusHandler {
private static AbstractRipper ripper;
+ private ResourceBundle rb = Utils.getResourceBundle();
+
+ private void updateQueueLabel() {
+ if (queueListModel.size() > 0) {
+ optionQueue.setText( rb.getString("Queue") + " (" + queueListModel.size() + ")");
+ } else {
+ optionQueue.setText(rb.getString("Queue"));
+ }
+ }
+
+
private static void addCheckboxListener(JCheckBox checkBox, String configString) {
checkBox.addActionListener(arg0 -> {
Utils.setConfigBoolean(configString, checkBox.isSelected());
@@ -289,7 +298,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
gbc.gridx = 3; ripPanel.add(stopButton, gbc);
gbc.weightx = 1;
- statusLabel = new JLabel("Inactive");
+ statusLabel = new JLabel(rb.getString("inactive"));
statusLabel.setHorizontalAlignment(JLabel.CENTER);
openButton = new JButton();
openButton.setVisible(false);
@@ -307,10 +316,10 @@ public final class MainWindow implements Runnable, RipStatusHandler {
JPanel optionsPanel = new JPanel(new GridBagLayout());
optionsPanel.setBorder(emptyBorder);
- optionLog = new JButton("Log");
- optionHistory = new JButton("History");
- optionQueue = new JButton("Queue");
- optionConfiguration = new JButton("Configuration");
+ optionLog = new JButton(rb.getString("Log"));
+ optionHistory = new JButton(rb.getString("History"));
+ optionQueue = new JButton(rb.getString("Queue"));
+ optionConfiguration = new JButton(rb.getString("Configuration"));
optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
optionQueue.setFont(optionLog.getFont().deriveFont(Font.PLAIN));
@@ -402,9 +411,9 @@ public final class MainWindow implements Runnable, RipStatusHandler {
historyTable.getColumnModel().getColumn(i).setPreferredWidth(width);
}
JScrollPane historyTableScrollPane = new JScrollPane(historyTable);
- historyButtonRemove = new JButton("Remove");
- historyButtonClear = new JButton("Clear");
- historyButtonRerip = new JButton("Re-rip Checked");
+ historyButtonRemove = new JButton(rb.getString("remove"));
+ historyButtonClear = new JButton(rb.getString("clear"));
+ historyButtonRerip = new JButton(rb.getString("re-rip.checked"));
gbc.gridx = 0;
// History List Panel
JPanel historyTablePanel = new JPanel(new GridBagLayout());
@@ -440,11 +449,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
for (String item : Utils.getConfigList("queue")) {
queueListModel.addElement(item);
}
- if (queueListModel.size() > 0) {
- optionQueue.setText("Queue (" + queueListModel.size() + ")");
- } else {
- optionQueue.setText("Queue");
- }
+ updateQueueLabel();
gbc.gridx = 0;
JPanel queueListPanel = new JPanel(new GridBagLayout());
gbc.fill = GridBagConstraints.BOTH;
@@ -459,27 +464,27 @@ public final class MainWindow implements Runnable, RipStatusHandler {
configurationPanel.setBorder(emptyBorder);
configurationPanel.setVisible(false);
// TODO Configuration components
- configUpdateButton = new JButton("Check for updates");
- configUpdateLabel = new JLabel("Current version: " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT);
- JLabel configThreadsLabel = new JLabel("Maximum download threads:", JLabel.RIGHT);
- JLabel configTimeoutLabel = new JLabel("Timeout (in milliseconds):", JLabel.RIGHT);
- JLabel configRetriesLabel = new JLabel("Retry download count:", JLabel.RIGHT);
+ configUpdateButton = new JButton(rb.getString("check.for.updates"));
+ configUpdateLabel = new JLabel( rb.getString("current.version") + ": " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT);
+ JLabel configThreadsLabel = new JLabel(rb.getString("max.download.threads") + ":", JLabel.RIGHT);
+ JLabel configTimeoutLabel = new JLabel(rb.getString("timeout.mill"), JLabel.RIGHT);
+ JLabel configRetriesLabel = new JLabel(rb.getString("retry.download.count"), JLabel.RIGHT);
configThreadsText = new JTextField(Integer.toString(Utils.getConfigInteger("threads.size", 3)));
configTimeoutText = new JTextField(Integer.toString(Utils.getConfigInteger("download.timeout", 60000)));
configRetriesText = new JTextField(Integer.toString(Utils.getConfigInteger("download.retries", 3)));
- configOverwriteCheckbox = addNewCheckbox("Overwrite existing files?", "file.overwrite", false);
- configAutoupdateCheckbox = addNewCheckbox("Auto-update?", "auto.update", true);
- configPlaySound = addNewCheckbox("Sound when rip completes", "play.sound", false);
- configShowPopup = addNewCheckbox("Notification when rip starts", "download.show_popup", false);
- configSaveOrderCheckbox = addNewCheckbox("Preserve order", "download.save_order", true);
- configSaveLogs = addNewCheckbox("Save logs", "log.save", false);
- configSaveURLsOnly = addNewCheckbox("Save URLs only", "urls_only.save", false);
- configSaveAlbumTitles = addNewCheckbox("Save album titles", "album_titles.save", true);
- configClipboardAutorip = addNewCheckbox("Autorip from Clipboard", "clipboard.autorip", false);
- configSaveDescriptions = addNewCheckbox("Save descriptions", "descriptions.save", true);
- configPreferMp4 = addNewCheckbox("Prefer MP4 over GIF","prefer.mp4", false);
- configWindowPosition = addNewCheckbox("Restore window position", "window.position", true);
- configURLHistoryCheckbox = addNewCheckbox("Remember URL history", "remember.url_history", true);
+ configOverwriteCheckbox = addNewCheckbox(rb.getString("overwrite.existing.files"), "file.overwrite", false);
+ configAutoupdateCheckbox = addNewCheckbox(rb.getString("auto.update"), "auto.update", true);
+ configPlaySound = addNewCheckbox(rb.getString("sound.when.rip.completes"), "play.sound", false);
+ configShowPopup = addNewCheckbox(rb.getString("notification.when.rip.starts"), "download.show_popup", false);
+ configSaveOrderCheckbox = addNewCheckbox(rb.getString("preserve.order"), "download.save_order", true);
+ configSaveLogs = addNewCheckbox(rb.getString("save.logs"), "log.save", false);
+ configSaveURLsOnly = addNewCheckbox(rb.getString("save.urls.only"), "urls_only.save", false);
+ configSaveAlbumTitles = addNewCheckbox(rb.getString("save.album.titles"), "album_titles.save", true);
+ configClipboardAutorip = addNewCheckbox(rb.getString("autorip.from.clipboard"), "clipboard.autorip", false);
+ configSaveDescriptions = addNewCheckbox(rb.getString("save.descriptions"), "descriptions.save", true);
+ configPreferMp4 = addNewCheckbox(rb.getString("prefer.mp4.over.gif"),"prefer.mp4", false);
+ configWindowPosition = addNewCheckbox(rb.getString("restore.window.position"), "window.position", true);
+ configURLHistoryCheckbox = addNewCheckbox(rb.getString("remember.url.history"), "remember.url_history", true);
configLogLevelCombobox = new JComboBox(new String[] {"Log level: Error", "Log level: Warn", "Log level: Info", "Log level: Debug"});
configLogLevelCombobox.setSelectedItem(Utils.getConfigString("log.level", "Log level: Debug"));
@@ -785,11 +790,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
queueListModel.addListDataListener(new ListDataListener() {
@Override
public void intervalAdded(ListDataEvent arg0) {
- if (queueListModel.size() > 0) {
- optionQueue.setText("Queue (" + queueListModel.size() + ")");
- } else {
- optionQueue.setText("Queue");
- }
+ updateQueueLabel();
if (!isRipping) {
ripNextAlbum();
}
@@ -966,7 +967,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
HISTORY.clear();
if (historyFile.exists()) {
try {
- logger.info("Loading history from " + historyFile.getCanonicalPath());
+ logger.info(rb.getString("loading.history.from") + " " + historyFile.getCanonicalPath());
HISTORY.fromFile(historyFile.getCanonicalPath());
} catch (IOException e) {
logger.error("Failed to load history from file " + historyFile, e);
@@ -979,7 +980,7 @@ public final class MainWindow implements Runnable, RipStatusHandler {
JOptionPane.ERROR_MESSAGE);
}
} else {
- logger.info("Loading history from configuration");
+ logger.info(rb.getString("loading.history.from.configuration"));
HISTORY.fromList(Utils.getConfigList("download.history"));
if (HISTORY.toList().size() == 0) {
// Loaded from config, still no entries.
@@ -1025,17 +1026,13 @@ public final class MainWindow implements Runnable, RipStatusHandler {
return;
}
String nextAlbum = (String) queueListModel.remove(0);
- if (queueListModel.isEmpty()) {
- optionQueue.setText("Queue");
- } else {
- optionQueue.setText("Queue (" + queueListModel.size() + ")");
- }
+ updateQueueLabel();
Thread t = ripAlbum(nextAlbum);
if (t == null) {
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
- logger.error("Interrupted while waiting to rip next album", ie);
+ logger.error(rb.getString("interrupted.while.waiting.to.rip.next.album"), ie);
}
ripNextAlbum();
} else {
diff --git a/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java b/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java
index 11d18771..38e88ae7 100644
--- a/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java
+++ b/src/main/java/com/rarchives/ripme/ui/UpdateUtils.java
@@ -21,7 +21,7 @@ import com.rarchives.ripme.utils.Utils;
public class UpdateUtils {
private static final Logger logger = Logger.getLogger(UpdateUtils.class);
- private static final String DEFAULT_VERSION = "1.7.44";
+ private static final String DEFAULT_VERSION = "1.7.45";
private static final String REPO_NAME = "ripmeapp/ripme";
private static final String updateJsonURL = "https://raw.githubusercontent.com/" + REPO_NAME + "/master/ripme.json";
private static final String mainFileName = "ripme.jar";
diff --git a/src/main/java/com/rarchives/ripme/utils/UTF8Control.java b/src/main/java/com/rarchives/ripme/utils/UTF8Control.java
new file mode 100644
index 00000000..6cd81bbb
--- /dev/null
+++ b/src/main/java/com/rarchives/ripme/utils/UTF8Control.java
@@ -0,0 +1,46 @@
+package com.rarchives.ripme.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+
+// Code taken from https://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle/4660195#4660195
+
+public class UTF8Control extends ResourceBundle.Control {
+ public ResourceBundle newBundle
+ (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
+ throws IllegalAccessException, InstantiationException, IOException
+ {
+ // The below is a copy of the default implementation.
+ String bundleName = toBundleName(baseName, locale);
+ String resourceName = toResourceName(bundleName, "properties");
+ ResourceBundle bundle = null;
+ InputStream stream = null;
+ if (reload) {
+ URL url = loader.getResource(resourceName);
+ if (url != null) {
+ URLConnection connection = url.openConnection();
+ if (connection != null) {
+ connection.setUseCaches(false);
+ stream = connection.getInputStream();
+ }
+ }
+ } else {
+ stream = loader.getResourceAsStream(resourceName);
+ }
+ if (stream != null) {
+ try {
+ // Only this line is changed to make it to read properties files as UTF-8.
+ bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
+ } finally {
+ stream.close();
+ }
+ }
+ return bundle;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rarchives/ripme/utils/Utils.java b/src/main/java/com/rarchives/ripme/utils/Utils.java
index 9517c528..cd1048df 100644
--- a/src/main/java/com/rarchives/ripme/utils/Utils.java
+++ b/src/main/java/com/rarchives/ripme/utils/Utils.java
@@ -1,9 +1,6 @@
package com.rarchives.ripme.utils;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URISyntaxException;
import java.net.URL;
@@ -579,4 +576,19 @@ public class Utils {
}
return domainCookies;
}
+
+ public static ResourceBundle getResourceBundle() {
+ if (!getConfigString("lang", "").equals("")) {
+ String[] langCode = getConfigString("lang", "").split("_");
+ logger.info("Setting locale to " + getConfigString("lang", ""));
+ return ResourceBundle.getBundle("LabelsBundle", new Locale(langCode[0], langCode[1]), new UTF8Control());
+ }
+ try {
+ ResourceBundle rb = ResourceBundle.getBundle("LabelsBundle", Locale.getDefault(), new UTF8Control());
+ return rb;
+ } catch (MissingResourceException e) {
+ ResourceBundle rb = ResourceBundle.getBundle("LabelsBundle", Locale.ROOT);
+ return rb;
+ }
+ }
}
diff --git a/src/main/resources/LabelsBundle.properties b/src/main/resources/LabelsBundle.properties
new file mode 100644
index 00000000..3a42ab0c
--- /dev/null
+++ b/src/main/resources/LabelsBundle.properties
@@ -0,0 +1,37 @@
+Log = Log
+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
\ No newline at end of file
diff --git a/src/main/resources/LabelsBundle_de_DE.properties b/src/main/resources/LabelsBundle_de_DE.properties
new file mode 100644
index 00000000..da1fc8e2
--- /dev/null
+++ b/src/main/resources/LabelsBundle_de_DE.properties
@@ -0,0 +1,38 @@
+Log = Log
+History = Verlauf
+created = erstellt
+modified = geändert
+Queue = Queue
+Configuration = Konfiguration
+
+# Keys for the Configuration menu
+
+current.version = Aktuelle Version
+check.for.updates = Suche nach Aktualisierungen
+auto.update = Automatisch Aktualisieren?
+max.download.threads = Maximum download threads
+timeout.mill = Timeout (in milliseconds):
+retry.download.count = Anzahl der Downloadversuche
+overwrite.existing.files = Überschreibe bereits existierende Dateien?
+sound.when.rip.completes = Ton abspielen bei fertigem Download
+preserve.order = Reihenfolge beibehalten
+save.logs = Speichere Logs
+notification.when.rip.starts = Benachrichtigung wenn Download startet
+save.urls.only = Speicher nur URLs
+save.album.titles = Speichere Albumtitels
+autorip.from.clipboard = Automatisch Downloaden von der Zwischenablage
+save.descriptions = Speichere Beschreibungen
+prefer.mp4.over.gif = Bevorzuge MP4 über GIF
+restore.window.position = Wieder herstellen der Fensterposition
+remember.url.history = Erinnere URL Verlauf
+loading.history.from = Lade Verlauf von
+
+# Misc UI keys
+
+loading.history.from.configuration = Lade Verlauf aus Konfiguration
+interrupted.while.waiting.to.rip.next.album = Unterbrochen während Download des nächsten Albums
+inactive = Inaktiv
+re-rip.checked = Re-rip Überprüft
+remove = Entfernen
+clear = Leeren
+
diff --git a/src/main/resources/LabelsBundle_es_ES.properties b/src/main/resources/LabelsBundle_es_ES.properties
new file mode 100644
index 00000000..a1aa5a4a
--- /dev/null
+++ b/src/main/resources/LabelsBundle_es_ES.properties
@@ -0,0 +1,37 @@
+Log = Log
+History = Historia
+created = creado
+modified = modificado
+Queue = Cola
+Configuration = Configuracion
+
+# Keys for the Configuration menu
+
+current.version = Version Actual
+check.for.updates = Buscar actualizaciones
+auto.update = Auto-actualizar?
+max.download.threads = Maximos procesos de descarga
+timeout.mill = Timeout (in milliseconds):
+retry.download.count = Numero de reintentos de descarga
+overwrite.existing.files = Sobreescribir archivos existentes?
+sound.when.rip.completes = Sonar cuando el Rip termina
+preserve.order = Mantener orden
+save.logs = Guardar logs
+notification.when.rip.starts = Notificar cuando el Rip comienza
+save.urls.only = Guardar solamente URLs
+save.album.titles = Guardar titulos de albunes
+autorip.from.clipboard = Autorip desde Portapapeles
+save.descriptions = Guardar descripciones
+prefer.mp4.over.gif = Preferir MP4 sobre GIF
+restore.window.position = Restaurar posicion de ventana
+remember.url.history = Recordar historia URL
+loading.history.from = Cargando historia desde
+
+# Misc UI keys
+
+loading.history.from.configuration = Cargando historia desde la configuracion
+interrupted.while.waiting.to.rip.next.album = Interrumpido esperando el Rip del proximo album
+inactive = Inactivo
+re-rip.checked = Re-rip marcado
+remove = Quitar
+clear = Limpiar
\ No newline at end of file
diff --git a/src/main/resources/LabelsBundle_fr_CH.properties b/src/main/resources/LabelsBundle_fr_CH.properties
new file mode 100644
index 00000000..1e23645b
--- /dev/null
+++ b/src/main/resources/LabelsBundle_fr_CH.properties
@@ -0,0 +1,37 @@
+Log = Journal
+History = Historique
+created = créé le
+modified = modifié le
+Queue = File d'attente
+Configuration = Configuration
+
+# Keys for the Configuration menu
+
+current.version = Version actuelle
+check.for.updates = Vérifier mises à jour
+auto.update = Mises à jour automatiques?
+max.download.threads = Nombre de téléchargements parallèles maximum
+timeout.mill = Délai d'expiration (en millisecondes):
+retry.download.count = Nombre d'essais téléchargement
+overwrite.existing.files = Remplacer fichiers existants ?
+sound.when.rip.completes = Son lorsque le rip est terminé
+preserve.order = Conserver l'ordre
+save.logs = Enregistrer journaux
+notification.when.rip.starts = Notification lorsqu'un rip commence
+save.urls.only = Enregistrer URL uniquement
+save.album.titles = Enregistrer titres d'album
+autorip.from.clipboard = Autorip depuis presse-papier
+save.descriptions = Enregistrer descriptions
+prefer.mp4.over.gif = Préférer MP4 à GIF
+restore.window.position = Restaurer la position de la fenêtre
+remember.url.history = Se souvenir de l'historique des URL
+loading.history.from = Charger l'historique depuis
+
+# Misc UI keys
+
+loading.history.from.configuration = Charger l'historique depuis la configuration
+interrupted.while.waiting.to.rip.next.album = Interrompu lors de l'attente pour ripper le prochain album
+inactive = Inactif
+re-rip.checked = Re-rip vérifié
+remove = Enlever
+clear = Effacer
\ No newline at end of file
diff --git a/src/main/resources/LabelsBundle_pt_PT.properties b/src/main/resources/LabelsBundle_pt_PT.properties
new file mode 100644
index 00000000..61581728
--- /dev/null
+++ b/src/main/resources/LabelsBundle_pt_PT.properties
@@ -0,0 +1,37 @@
+Log = Registo
+History = Histórico
+created = criado
+modified = modificado
+Queue = Fila
+Configuration = Configuração
+
+# Keys for the Configuration menu
+
+current.version = Versão atual
+check.for.updates = Verificar atualizações
+auto.update = Atualização automática?
+max.download.threads = Número máximo de processos de transferência
+timeout.mill = Timeout (em milissegundos):
+retry.download.count = Número de novas tentativas de transferência
+overwrite.existing.files = Sobrescrever ficheiros existentes?
+sound.when.rip.completes = Notificar quando o rip é concluído
+preserve.order = Manter a ordem
+save.logs = Guardar registos
+notification.when.rip.starts = Notificar quando o rip começar
+save.urls.only = Apenas guardar URLs
+save.album.titles = Guardar os títulos de álbuns
+autorip.from.clipboard = Autorip da área de transferência
+save.descriptions = Guardar descrições
+prefer.mp4.over.gif = Preferir MP4 a GIF
+restore.window.position = Restaurar posição da janela
+remember.url.history = Lembrar histórico de URL
+loading.history.from = Carregar histórico de
+
+# Misc UI keys
+
+loading.history.from.configuration = A carregar o histórico da configuração
+interrupted.while.waiting.to.rip.next.album = Interrompido durante a espera do rip do próximo álbum
+inactive = Inativo
+re-rip.checked = Re-rip verificado
+remove = Remover
+clear = Limpar
diff --git a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/VideoRippersTest.java b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/VideoRippersTest.java
index ae31192b..6a7df184 100644
--- a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/VideoRippersTest.java
+++ b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/VideoRippersTest.java
@@ -38,14 +38,17 @@ public class VideoRippersTest extends RippersTest {
}
}
- public void testTwitchVideoRipper() throws IOException {
- List contentURLs = new ArrayList<>();
- contentURLs.add(new URL("https://clips.twitch.tv/FaithfulIncredulousPotTBCheesePull"));
- for (URL url : contentURLs) {
- TwitchVideoRipper ripper = new TwitchVideoRipper(url);
- videoTestHelper(ripper);
- }
- }
+
+// Test disbaled. See https://github.com/RipMeApp/ripme/issues/574
+
+// public void testTwitchVideoRipper() throws IOException {
+// List contentURLs = new ArrayList<>();
+// contentURLs.add(new URL("https://clips.twitch.tv/FaithfulIncredulousPotTBCheesePull"));
+// for (URL url : contentURLs) {
+// TwitchVideoRipper ripper = new TwitchVideoRipper(url);
+// videoTestHelper(ripper);
+// }
+// }
public void testXhamsterRipper() throws IOException {
List contentURLs = new ArrayList<>();