From c17a4d48551f8bdb16ec679e91c1913d6846f095 Mon Sep 17 00:00:00 2001 From: buzzlightmonth <44553885+buzzlightmonth@users.noreply.github.com> Date: Wed, 23 Jan 2019 16:37:37 +0100 Subject: [PATCH 01/16] Removed unused imports of AlbumRipper --- .../com/rarchives/ripme/ripper/rippers/NewsfilterRipper.java | 4 ---- .../java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java | 3 --- .../com/rarchives/ripme/ripper/rippers/PornhubRipper.java | 2 -- 3 files changed, 9 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/NewsfilterRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/NewsfilterRipper.java index eee733db..bafa3690 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/NewsfilterRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/NewsfilterRipper.java @@ -10,14 +10,10 @@ import java.util.regex.Pattern; import com.rarchives.ripme.ripper.AbstractHTMLRipper; import com.rarchives.ripme.utils.Http; -import org.jsoup.Connection; -import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import com.rarchives.ripme.ripper.AlbumRipper; - public class NewsfilterRipper extends AbstractHTMLRipper { private static final String HOST = "newsfilter"; diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java index b525a39a..86079edc 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/NfsfwRipper.java @@ -13,11 +13,8 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import com.rarchives.ripme.ripper.AlbumRipper; import com.rarchives.ripme.ripper.DownloadThreadPool; -import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Http; -import com.rarchives.ripme.utils.Utils; public class NfsfwRipper extends AbstractHTMLRipper { diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/PornhubRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/PornhubRipper.java index eb7a421b..197bdcbd 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/PornhubRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/PornhubRipper.java @@ -14,9 +14,7 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import com.rarchives.ripme.ripper.AlbumRipper; import com.rarchives.ripme.ripper.DownloadThreadPool; -import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Http; import com.rarchives.ripme.utils.Utils; From 3b22af3cda5b31d433e8e6451ad1c5091783ee1b Mon Sep 17 00:00:00 2001 From: buzzlightmonth <44553885+buzzlightmonth@users.noreply.github.com> Date: Wed, 23 Jan 2019 17:54:13 +0100 Subject: [PATCH 02/16] Removed references of AlbumRipper in the MotherlessRipper --- .../ripper/rippers/MotherlessRipper.java | 84 ++++++++++++------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/MotherlessRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/MotherlessRipper.java index b2fee8e5..9b71d756 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/MotherlessRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/MotherlessRipper.java @@ -3,19 +3,21 @@ package com.rarchives.ripme.ripper.rippers; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +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 com.rarchives.ripme.ripper.AlbumRipper; +import com.rarchives.ripme.ripper.AbstractHTMLRipper; import com.rarchives.ripme.ripper.DownloadThreadPool; import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Http; import com.rarchives.ripme.utils.Utils; -public class MotherlessRipper extends AlbumRipper { +public class MotherlessRipper extends AbstractHTMLRipper { private static final String DOMAIN = "motherless.com", HOST = "motherless"; @@ -37,6 +39,52 @@ public class MotherlessRipper extends AlbumRipper { return url.getHost().endsWith(DOMAIN); } + @Override + protected String getDomain() { + return DOMAIN; + } + + @Override + protected Document getFirstPage() throws IOException { + return Http.url(url).referrer("http://motherless.com").get(); + } + + @Override + protected List getURLsFromPage(Document page) { + List pageURLs = new ArrayList<>(); + + for (Element thumb : page.select("div.thumb a.img-container")) { + if (isStopped()) { + break; + } + String thumbURL = thumb.attr("href"); + if (thumbURL.contains("pornmd.com")) { + continue; + } + + String url; + if (!thumbURL.startsWith("http")) { + url = "http://" + DOMAIN + thumbURL; + } else { + url = thumbURL; + } + pageURLs.add(url); + + if (isThisATest()) { + break; + } + } + + return pageURLs; + } + + @Override + protected void downloadURL(URL url, int index) { + // Create thread for finding image at "url" page + MotherlessImageThread mit = new MotherlessImageThread(url, index); + motherlessThreadPool.addThread(mit); + } + @Override public String getHost() { return HOST; @@ -77,34 +125,14 @@ public class MotherlessRipper extends AlbumRipper { } LOGGER.info("Retrieving " + nextURL); sendUpdate(STATUS.LOADING_RESOURCE, nextURL); - Document doc = Http.url(nextURL) - .referrer("http://motherless.com") - .get(); - for (Element thumb : doc.select("div.thumb a.img-container")) { - if (isStopped()) { - break; - } - String thumbURL = thumb.attr("href"); - if (thumbURL.contains("pornmd.com")) { - continue; - } - URL url; - if (!thumbURL.startsWith("http")) { - url = new URL("http://" + DOMAIN + thumbURL); - } - else { - url = new URL(thumbURL); - } - index += 1; + Document doc = getFirstPage(); + List URLs = getURLsFromPage(doc); - // Create thread for finding image at "url" page - MotherlessImageThread mit = new MotherlessImageThread(url, index); - motherlessThreadPool.addThread(mit); - - if (isThisATest()) { - break; - } + for (String url: URLs) { + downloadURL(new URL(url), index); + index ++; } + if (isThisATest()) { break; } From e84b776b4e2241ead783ab165ce543cf06ab4e4d Mon Sep 17 00:00:00 2001 From: buzzlightmonth <44553885+buzzlightmonth@users.noreply.github.com> Date: Wed, 23 Jan 2019 18:55:03 +0100 Subject: [PATCH 03/16] [untested] Removed references in VkRipper --- .../ripme/ripper/rippers/VkRipper.java | 269 ++++++++++-------- 1 file changed, 153 insertions(+), 116 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/VkRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/VkRipper.java index b2472cc9..99310dc4 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/VkRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/VkRipper.java @@ -3,33 +3,171 @@ package com.rarchives.ripme.ripper.rippers; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.rarchives.ripme.ripper.AbstractJSONRipper; import org.json.JSONArray; import org.json.JSONObject; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; -import com.rarchives.ripme.ripper.AlbumRipper; import com.rarchives.ripme.utils.Http; import com.rarchives.ripme.utils.Utils; -public class VkRipper extends AlbumRipper { +public class VkRipper extends AbstractJSONRipper { private static final String DOMAIN = "vk.com", HOST = "vk"; + enum RipType { VIDEO, IMAGE } + + private RipType RIP_TYPE; + private String oid; + public VkRipper(URL url) throws IOException { super(url); } + @Override + public String getHost() { + return HOST; + } + + @Override + protected String getDomain() { + return DOMAIN; + } + + @Override + protected JSONObject getFirstPage() throws IOException { + if (RIP_TYPE == RipType.VIDEO) { + oid = getGID(this.url).replace("videos", ""); + String u = "http://vk.com/al_video.php"; + Map postData = new HashMap<>(); + postData.put("al", "1"); + postData.put("act", "load_videos_silent"); + postData.put("offset", "0"); + postData.put("oid", oid); + Document doc = Http.url(u) + .referrer(this.url) + .ignoreContentType() + .data(postData) + .post(); + String[] jsonStrings = doc.toString().split(""); + return new JSONObject(jsonStrings[jsonStrings.length - 1]); + } else { + Map photoIDsToURLs = new HashMap<>(); + int offset = 0; + while (true) { + LOGGER.info(" Retrieving " + this.url); + Map postData = new HashMap<>(); + postData.put("al", "1"); + postData.put("offset", Integer.toString(offset)); + postData.put("part", "1"); + Document doc = Http.url(this.url) + .referrer(this.url) + .ignoreContentType() + .data(postData) + .post(); + + String body = doc.toString(); + if (!body.contains(" elements = doc.select("a"); + Set photoIDsToGet = new HashSet<>(); + for (Element a : elements) { + if (!a.attr("onclick").contains("showPhoto('")) { + LOGGER.error("a: " + a); + continue; + } + String photoID = a.attr("onclick"); + photoID = photoID.substring(photoID.indexOf("showPhoto('") + "showPhoto('".length()); + photoID = photoID.substring(0, photoID.indexOf("'")); + if (!photoIDsToGet.contains(photoID)) { + photoIDsToGet.add(photoID); + } + } + for (String photoID : photoIDsToGet) { + if (!photoIDsToURLs.containsKey(photoID)) { + try { + photoIDsToURLs.putAll(getPhotoIDsToURLs(photoID)); + } catch (IOException e) { + LOGGER.error("Exception while retrieving photo id " + photoID, e); + continue; + } + } + if (!photoIDsToURLs.containsKey(photoID)) { + LOGGER.error("Could not find URL for photo ID: " + photoID); + continue; + } + if (isStopped() || isThisATest()) { + break; + } + } + + if (elements.size() < 40 || isStopped() || isThisATest()) { + break; + } + offset += elements.size(); + } + // Slight hack to make this into effectively a JSON ripper + return new JSONObject(photoIDsToURLs); + } + } + + @Override + protected List getURLsFromJSON(JSONObject page) { + List pageURLs = new ArrayList<>(); + if (RIP_TYPE == RipType.VIDEO) { + JSONArray videos = page.getJSONArray("all"); + LOGGER.info("Found " + videos.length() + " videos"); + + for (int i = 0; i < videos.length(); i++) { + JSONArray jsonVideo = videos.getJSONArray(i); + int vidid = jsonVideo.getInt(1); + String videoURL; + try { + videoURL = com.rarchives.ripme.ripper.rippers.video.VkRipper.getVideoURLAtPage( + "http://vk.com/video" + oid + "_" + vidid); + } catch (IOException e) { + LOGGER.error("Error while ripping video id: " + vidid); + return pageURLs; + } + pageURLs.add(videoURL); + } + } else { + Iterator keys = page.keys(); + while (keys.hasNext()) { + pageURLs.add(page.getString((String) keys.next())); + } + } + return pageURLs; + } + + @Override + protected void downloadURL(URL url, int index) { + if (RIP_TYPE == RipType.VIDEO) { + String prefix = ""; + if (Utils.getConfigBoolean("download.save_order", true)) { + prefix = String.format("%03d_", index + 1); + } + addURLToDownload(url, prefix); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + LOGGER.error("Interrupted while waiting to fetch next video URL", e); + } + } else { + addURLToDownload(url); + } + } + @Override public boolean canRip(URL url) { if (!url.getHost().endsWith(DOMAIN)) { @@ -48,115 +186,19 @@ public class VkRipper extends AlbumRipper { @Override public void rip() throws IOException { if (this.url.toExternalForm().contains("/videos")) { - ripVideos(); + RIP_TYPE = RipType.VIDEO; + JSONObject json = getFirstPage(); + List URLs = getURLsFromJSON(json); + for (int index = 0; index < URLs.size(); index ++) { + downloadURL(new URL(URLs.get(index)), index); + } + waitForThreads(); } else { - ripImages(); + RIP_TYPE = RipType.IMAGE; } } - private void ripVideos() throws IOException { - String oid = getGID(this.url).replace("videos", ""); - String u = "http://vk.com/al_video.php"; - Map postData = new HashMap<>(); - postData.put("al", "1"); - postData.put("act", "load_videos_silent"); - postData.put("offset", "0"); - postData.put("oid", oid); - Document doc = Http.url(u) - .referrer(this.url) - .ignoreContentType() - .data(postData) - .post(); - String[] jsonStrings = doc.toString().split(""); - JSONObject json = new JSONObject(jsonStrings[jsonStrings.length - 1]); - JSONArray videos = json.getJSONArray("all"); - LOGGER.info("Found " + videos.length() + " videos"); - for (int i = 0; i < videos.length(); i++) { - JSONArray jsonVideo = videos.getJSONArray(i); - int vidid = jsonVideo.getInt(1); - String videoURL = com.rarchives.ripme.ripper.rippers.video.VkRipper.getVideoURLAtPage( - "http://vk.com/video" + oid + "_" + vidid); - String prefix = ""; - if (Utils.getConfigBoolean("download.save_order", true)) { - prefix = String.format("%03d_", i + 1); - } - addURLToDownload(new URL(videoURL), prefix); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - LOGGER.error("Interrupted while waiting to fetch next video URL", e); - break; - } - } - waitForThreads(); - } - - private void ripImages() throws IOException { - Map photoIDsToURLs = new HashMap<>(); - int offset = 0; - while (true) { - LOGGER.info(" Retrieving " + this.url); - - // al=1&offset=80&part=1 - Map postData = new HashMap<>(); - postData.put("al", "1"); - postData.put("offset", Integer.toString(offset)); - postData.put("part", "1"); - Document doc = Http.url(this.url) - .referrer(this.url) - .ignoreContentType() - .data(postData) - .post(); - - String body = doc.toString(); - if (!body.contains(" elements = doc.select("a"); - Set photoIDsToGet = new HashSet<>(); - for (Element a : elements) { - if (!a.attr("onclick").contains("showPhoto('")) { - LOGGER.error("a: " + a); - continue; - } - String photoID = a.attr("onclick"); - photoID = photoID.substring(photoID.indexOf("showPhoto('") + "showPhoto('".length()); - photoID = photoID.substring(0, photoID.indexOf("'")); - if (!photoIDsToGet.contains(photoID)) { - photoIDsToGet.add(photoID); - } - } - for (String photoID : photoIDsToGet) { - if (!photoIDsToURLs.containsKey(photoID)) { - try { - photoIDsToURLs.putAll(getPhotoIDsToURLs(photoID)); - } catch (IOException e) { - LOGGER.error("Exception while retrieving photo id " + photoID, e); - continue; - } - } - if (!photoIDsToURLs.containsKey(photoID)) { - LOGGER.error("Could not find URL for photo ID: " + photoID); - continue; - } - String url = photoIDsToURLs.get(photoID); - addURLToDownload(new URL(url)); - if (isStopped() || isThisATest()) { - break; - } - } - - if (elements.size() < 40 || isStopped() || isThisATest()) { - break; - } - offset += elements.size(); - } - waitForThreads(); - } - private Map getPhotoIDsToURLs(String photoID) throws IOException { Map photoIDsToURLs = new HashMap<>(); Map postData = new HashMap<>(); @@ -191,11 +233,6 @@ public class VkRipper extends AlbumRipper { return photoIDsToURLs; } - @Override - public String getHost() { - return HOST; - } - @Override public String getGID(URL url) throws MalformedURLException { Pattern p = Pattern.compile("^https?://(www\\.)?vk\\.com/(photos|album|videos)-?([a-zA-Z0-9_]+).*$"); From f35921d5b9fdd3b23dd181e88d5f1a2a0e1e16cc Mon Sep 17 00:00:00 2001 From: cyian-1756 Date: Fri, 22 Feb 2019 10:01:00 -0500 Subject: [PATCH 04/16] Added ripper for myreadingmanga.info --- .../ripper/rippers/MyreadingmangaRipper.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java new file mode 100644 index 00000000..5e900ee3 --- /dev/null +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java @@ -0,0 +1,66 @@ + +package com.rarchives.ripme.ripper.rippers; + +import com.rarchives.ripme.ripper.AbstractHTMLRipper; +import com.rarchives.ripme.utils.Http; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +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; + +public class MyreadingmangaRipper extends AbstractHTMLRipper { + + public MyreadingmangaRipper(URL url) throws IOException { + super(url); + } + + @Override + public String getHost() { + return "myreadingmanga"; + } + + @Override + public String getDomain() { + return "myreadingmanga.info"; + } + + @Override + public String getGID(URL url) throws MalformedURLException { + Pattern p = Pattern.compile("https://myreadingmanga.info/([a-zA-Z_\\-0-9]+)/?$"); + Matcher m = p.matcher(url.toExternalForm()); + if (m.matches()) { + return m.group(1); + } + + throw new MalformedURLException("Expected myreadingmanga.info URL format: " + + "myreadingmanga.info/title - got " + url + " instead"); + } + + @Override + public Document getFirstPage() throws IOException { + // "url" is an instance field of the superclass + return Http.url(url).get(); + } + + @Override + public List getURLsFromPage(Document doc) { + LOGGER.info(doc); + List result = new ArrayList<>(); + for (Element el : doc.select("div.separator > img")) { + String imageSource = el.attr("data-lazy-src"); + result.add(imageSource); + } + return result; + } + + @Override + public void downloadURL(URL url, int index) { + addURLToDownload(url, getPrefix(index)); + } + +} \ No newline at end of file From 3adc3e85313d3bcbe1135c561b0981024061ac33 Mon Sep 17 00:00:00 2001 From: cyian-1756 Date: Fri, 22 Feb 2019 10:04:59 -0500 Subject: [PATCH 05/16] Removed debugging statments --- .../rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java | 1 - .../ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java index 5e900ee3..b44a7164 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/MyreadingmangaRipper.java @@ -49,7 +49,6 @@ public class MyreadingmangaRipper extends AbstractHTMLRipper { @Override public List getURLsFromPage(Document doc) { - LOGGER.info(doc); List result = new ArrayList<>(); for (Element el : doc.select("div.separator > img")) { String imageSource = el.attr("data-lazy-src"); diff --git a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java new file mode 100644 index 00000000..3b52a071 --- /dev/null +++ b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java @@ -0,0 +1,4 @@ +package com.rarchives.ripme.tst.ripper.rippers; + +public class MyreadingmangaRipperTest { +} From 543cd09d4f5a846a8f40d54318d6ec646f8bab55 Mon Sep 17 00:00:00 2001 From: cyian-1756 Date: Fri, 22 Feb 2019 10:05:20 -0500 Subject: [PATCH 06/16] Added a test for Myreadingmanga --- .../tst/ripper/rippers/MyreadingmangaRipperTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java index 3b52a071..16c5de5e 100644 --- a/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java +++ b/src/test/java/com/rarchives/ripme/tst/ripper/rippers/MyreadingmangaRipperTest.java @@ -1,4 +1,13 @@ package com.rarchives.ripme.tst.ripper.rippers; -public class MyreadingmangaRipperTest { +import java.io.IOException; +import java.net.URL; +import com.rarchives.ripme.ripper.rippers.MyreadingmangaRipper; + + +public class MyreadingmangaRipperTest extends RippersTest { + public void testRip() throws IOException { + MyreadingmangaRipper ripper = new MyreadingmangaRipper(new URL("https://myreadingmanga.info/zelo-lee-brave-lover-dj-slave-market-jp/")); + testRipper(ripper); + } } From ff4cf384b2203995f69ff944929df2c59c48b0dd Mon Sep 17 00:00:00 2001 From: Tushar Date: Tue, 23 Apr 2019 13:41:31 +0530 Subject: [PATCH 07/16] Removed ref to AlbumRipper and copied required methods. --- .../ripme/ripper/AbstractHTMLRipper.java | 218 ++++++++++++++++- .../ripme/ripper/AbstractJSONRipper.java | 219 +++++++++++++++++- 2 files changed, 432 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/AbstractHTMLRipper.java b/src/main/java/com/rarchives/ripme/ripper/AbstractHTMLRipper.java index e1c7c507..3e3fdb18 100644 --- a/src/main/java/com/rarchives/ripme/ripper/AbstractHTMLRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/AbstractHTMLRipper.java @@ -2,21 +2,29 @@ package com.rarchives.ripme.ripper; import java.io.File; import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; +import java.util.HashMap; import java.util.List; - +import java.util.Map; import org.jsoup.nodes.Document; import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Utils; import com.rarchives.ripme.ui.MainWindow; +import com.rarchives.ripme.ui.RipStatusMessage; /** * Simplified ripper, designed for ripping from sites by parsing HTML. */ -public abstract class AbstractHTMLRipper extends AlbumRipper { +public abstract class AbstractHTMLRipper extends AbstractRipper { + + private Map itemsPending = Collections.synchronizedMap(new HashMap()); + private Map itemsCompleted = Collections.synchronizedMap(new HashMap()); + private Map itemsErrored = Collections.synchronizedMap(new HashMap()); protected AbstractHTMLRipper(URL url) throws IOException { super(url); @@ -262,4 +270,210 @@ public abstract class AbstractHTMLRipper extends AlbumRipper { } return prefix; } + + /* + * ------ Methods copied from AlbumRipper. ------ + * This removes AlbumnRipper's usage from this class. + */ + + protected boolean allowDuplicates() { + return false; + } + + @Override + /** + * Returns total amount of files attempted. + */ + public int getCount() { + return itemsCompleted.size() + itemsErrored.size(); + } + + @Override + /** + * Queues multiple URLs of single images to download from a single Album URL + */ + public boolean addURLToDownload(URL url, File saveAs, String referrer, Map cookies, Boolean getFileExtFromMIME) { + // Only download one file if this is a test. + if (super.isThisATest() && + (itemsPending.size() > 0 || itemsCompleted.size() > 0 || itemsErrored.size() > 0)) { + stop(); + return false; + } + if (!allowDuplicates() + && ( itemsPending.containsKey(url) + || itemsCompleted.containsKey(url) + || itemsErrored.containsKey(url) )) { + // Item is already downloaded/downloading, skip it. + LOGGER.info("[!] Skipping " + url + " -- already attempted: " + Utils.removeCWD(saveAs)); + return false; + } + if (Utils.getConfigBoolean("urls_only.save", false)) { + // Output URL to file + String urlFile = this.workingDir + File.separator + "urls.txt"; + try (FileWriter fw = new FileWriter(urlFile, true)) { + fw.write(url.toExternalForm()); + fw.write(System.lineSeparator()); + itemsCompleted.put(url, new File(urlFile)); + } catch (IOException e) { + LOGGER.error("Error while writing to " + urlFile, e); + } + } + else { + itemsPending.put(url, saveAs); + DownloadFileThread dft = new DownloadFileThread(url, saveAs, this, getFileExtFromMIME); + if (referrer != null) { + dft.setReferrer(referrer); + } + if (cookies != null) { + dft.setCookies(cookies); + } + threadPool.addThread(dft); + } + + return true; + } + + @Override + public boolean addURLToDownload(URL url, File saveAs) { + return addURLToDownload(url, saveAs, null, null, false); + } + + /** + * Queues image to be downloaded and saved. + * Uses filename from URL to decide filename. + * @param url + * URL to download + * @return + * True on success + */ + protected boolean addURLToDownload(URL url) { + // Use empty prefix and empty subdirectory + return addURLToDownload(url, "", ""); + } + + @Override + /** + * Cleans up & tells user about successful download + */ + public void downloadCompleted(URL url, File saveAs) { + if (observer == null) { + return; + } + try { + String path = Utils.removeCWD(saveAs); + RipStatusMessage msg = new RipStatusMessage(STATUS.DOWNLOAD_COMPLETE, path); + itemsPending.remove(url); + itemsCompleted.put(url, saveAs); + observer.update(this, msg); + + checkIfComplete(); + } catch (Exception e) { + LOGGER.error("Exception while updating observer: ", e); + } + } + + @Override + /** + * Cleans up & tells user about failed download. + */ + public void downloadErrored(URL url, String reason) { + if (observer == null) { + return; + } + itemsPending.remove(url); + itemsErrored.put(url, reason); + observer.update(this, new RipStatusMessage(STATUS.DOWNLOAD_ERRORED, url + " : " + reason)); + + checkIfComplete(); + } + + @Override + /** + * Tells user that a single file in the album they wish to download has + * already been downloaded in the past. + */ + public void downloadExists(URL url, File file) { + if (observer == null) { + return; + } + + itemsPending.remove(url); + itemsCompleted.put(url, file); + observer.update(this, new RipStatusMessage(STATUS.DOWNLOAD_WARN, url + " already saved as " + file.getAbsolutePath())); + + checkIfComplete(); + } + + /** + * Notifies observers and updates state if all files have been ripped. + */ + @Override + protected void checkIfComplete() { + if (observer == null) { + return; + } + if (itemsPending.isEmpty()) { + super.checkIfComplete(); + } + } + + /** + * Sets directory to save all ripped files to. + * @param url + * URL to define how the working directory should be saved. + * @throws + * IOException + */ + @Override + public void setWorkingDir(URL url) throws IOException { + String path = Utils.getWorkingDirectory().getCanonicalPath(); + if (!path.endsWith(File.separator)) { + path += File.separator; + } + String title; + if (Utils.getConfigBoolean("album_titles.save", true)) { + title = getAlbumTitle(this.url); + } else { + title = super.getAlbumTitle(this.url); + } + LOGGER.debug("Using album title '" + title + "'"); + + title = Utils.filesystemSafe(title); + path += title; + path = Utils.getOriginalDirectory(path) + File.separator; // check for case sensitive (unix only) + + this.workingDir = new File(path); + if (!this.workingDir.exists()) { + LOGGER.info("[+] Creating directory: " + Utils.removeCWD(this.workingDir)); + this.workingDir.mkdirs(); + } + LOGGER.debug("Set working directory to: " + this.workingDir); + } + + /** + * @return + * Integer between 0 and 100 defining the progress of the album rip. + */ + @Override + public int getCompletionPercentage() { + double total = itemsPending.size() + itemsErrored.size() + itemsCompleted.size(); + return (int) (100 * ( (total - itemsPending.size()) / total)); + } + + /** + * @return + * Human-readable information on the status of the current rip. + */ + @Override + public String getStatusText() { + StringBuilder sb = new StringBuilder(); + sb.append(getCompletionPercentage()) + .append("% ") + .append("- Pending: " ).append(itemsPending.size()) + .append(", Completed: ").append(itemsCompleted.size()) + .append(", Errored: " ).append(itemsErrored.size()); + return sb.toString(); + } + + } diff --git a/src/main/java/com/rarchives/ripme/ripper/AbstractJSONRipper.java b/src/main/java/com/rarchives/ripme/ripper/AbstractJSONRipper.java index 4455270e..d7e93fcb 100644 --- a/src/main/java/com/rarchives/ripme/ripper/AbstractJSONRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/AbstractJSONRipper.java @@ -1,19 +1,27 @@ package com.rarchives.ripme.ripper; +import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; +import java.util.HashMap; import java.util.List; - +import java.util.Map; import org.json.JSONObject; - +import com.rarchives.ripme.ui.RipStatusMessage; import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Utils; /** * Simplified ripper, designed for ripping from sites by parsing JSON. */ -public abstract class AbstractJSONRipper extends AlbumRipper { +public abstract class AbstractJSONRipper extends AbstractRipper { + + private Map itemsPending = Collections.synchronizedMap(new HashMap()); + private Map itemsCompleted = Collections.synchronizedMap(new HashMap()); + private Map itemsErrored = Collections.synchronizedMap(new HashMap()); protected AbstractJSONRipper(URL url) throws IOException { super(url); @@ -111,4 +119,209 @@ public abstract class AbstractJSONRipper extends AlbumRipper { } return prefix; } + + /* + * ------ Methods copied from AlbumRipper ------ + */ + + protected boolean allowDuplicates() { + return false; + } + + @Override + /** + * Returns total amount of files attempted. + */ + public int getCount() { + return itemsCompleted.size() + itemsErrored.size(); + } + + @Override + /** + * Queues multiple URLs of single images to download from a single Album URL + */ + public boolean addURLToDownload(URL url, File saveAs, String referrer, Map cookies, Boolean getFileExtFromMIME) { + // Only download one file if this is a test. + if (super.isThisATest() && + (itemsPending.size() > 0 || itemsCompleted.size() > 0 || itemsErrored.size() > 0)) { + stop(); + return false; + } + if (!allowDuplicates() + && ( itemsPending.containsKey(url) + || itemsCompleted.containsKey(url) + || itemsErrored.containsKey(url) )) { + // Item is already downloaded/downloading, skip it. + LOGGER.info("[!] Skipping " + url + " -- already attempted: " + Utils.removeCWD(saveAs)); + return false; + } + if (Utils.getConfigBoolean("urls_only.save", false)) { + // Output URL to file + String urlFile = this.workingDir + File.separator + "urls.txt"; + try (FileWriter fw = new FileWriter(urlFile, true)) { + fw.write(url.toExternalForm()); + fw.write(System.lineSeparator()); + itemsCompleted.put(url, new File(urlFile)); + } catch (IOException e) { + LOGGER.error("Error while writing to " + urlFile, e); + } + } + else { + itemsPending.put(url, saveAs); + DownloadFileThread dft = new DownloadFileThread(url, saveAs, this, getFileExtFromMIME); + if (referrer != null) { + dft.setReferrer(referrer); + } + if (cookies != null) { + dft.setCookies(cookies); + } + threadPool.addThread(dft); + } + + return true; + } + + @Override + public boolean addURLToDownload(URL url, File saveAs) { + return addURLToDownload(url, saveAs, null, null, false); + } + + /** + * Queues image to be downloaded and saved. + * Uses filename from URL to decide filename. + * @param url + * URL to download + * @return + * True on success + */ + protected boolean addURLToDownload(URL url) { + // Use empty prefix and empty subdirectory + return addURLToDownload(url, "", ""); + } + + @Override + /** + * Cleans up & tells user about successful download + */ + public void downloadCompleted(URL url, File saveAs) { + if (observer == null) { + return; + } + try { + String path = Utils.removeCWD(saveAs); + RipStatusMessage msg = new RipStatusMessage(STATUS.DOWNLOAD_COMPLETE, path); + itemsPending.remove(url); + itemsCompleted.put(url, saveAs); + observer.update(this, msg); + + checkIfComplete(); + } catch (Exception e) { + LOGGER.error("Exception while updating observer: ", e); + } + } + + @Override + /** + * Cleans up & tells user about failed download. + */ + public void downloadErrored(URL url, String reason) { + if (observer == null) { + return; + } + itemsPending.remove(url); + itemsErrored.put(url, reason); + observer.update(this, new RipStatusMessage(STATUS.DOWNLOAD_ERRORED, url + " : " + reason)); + + checkIfComplete(); + } + + @Override + /** + * Tells user that a single file in the album they wish to download has + * already been downloaded in the past. + */ + public void downloadExists(URL url, File file) { + if (observer == null) { + return; + } + + itemsPending.remove(url); + itemsCompleted.put(url, file); + observer.update(this, new RipStatusMessage(STATUS.DOWNLOAD_WARN, url + " already saved as " + file.getAbsolutePath())); + + checkIfComplete(); + } + + /** + * Notifies observers and updates state if all files have been ripped. + */ + @Override + protected void checkIfComplete() { + if (observer == null) { + return; + } + if (itemsPending.isEmpty()) { + super.checkIfComplete(); + } + } + + /** + * Sets directory to save all ripped files to. + * @param url + * URL to define how the working directory should be saved. + * @throws + * IOException + */ + @Override + public void setWorkingDir(URL url) throws IOException { + String path = Utils.getWorkingDirectory().getCanonicalPath(); + if (!path.endsWith(File.separator)) { + path += File.separator; + } + String title; + if (Utils.getConfigBoolean("album_titles.save", true)) { + title = getAlbumTitle(this.url); + } else { + title = super.getAlbumTitle(this.url); + } + LOGGER.debug("Using album title '" + title + "'"); + + title = Utils.filesystemSafe(title); + path += title; + path = Utils.getOriginalDirectory(path) + File.separator; // check for case sensitive (unix only) + + this.workingDir = new File(path); + if (!this.workingDir.exists()) { + LOGGER.info("[+] Creating directory: " + Utils.removeCWD(this.workingDir)); + this.workingDir.mkdirs(); + } + LOGGER.debug("Set working directory to: " + this.workingDir); + } + + /** + * @return + * Integer between 0 and 100 defining the progress of the album rip. + */ + @Override + public int getCompletionPercentage() { + double total = itemsPending.size() + itemsErrored.size() + itemsCompleted.size(); + return (int) (100 * ( (total - itemsPending.size()) / total)); + } + + /** + * @return + * Human-readable information on the status of the current rip. + */ + @Override + public String getStatusText() { + StringBuilder sb = new StringBuilder(); + sb.append(getCompletionPercentage()) + .append("% ") + .append("- Pending: " ).append(itemsPending.size()) + .append(", Completed: ").append(itemsCompleted.size()) + .append(", Errored: " ).append(itemsErrored.size()); + return sb.toString(); + } + + } From ba674d4d4bc6fd5f75b6ac8adeaae35459801a2a Mon Sep 17 00:00:00 2001 From: Tushar Date: Fri, 26 Apr 2019 00:50:03 +0530 Subject: [PATCH 08/16] Removed AlbumRipper usage from AbstractRipper. --- .../rarchives/ripme/ripper/AbstractRipper.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java b/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java index 1220c5f4..3653b9f0 100644 --- a/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/AbstractRipper.java @@ -1,7 +1,11 @@ package com.rarchives.ripme.ripper; import java.awt.Desktop; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; @@ -9,21 +13,17 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Observable; - -import com.rarchives.ripme.App; +import java.util.Scanner; import org.apache.log4j.FileAppender; import org.apache.log4j.Logger; import org.jsoup.HttpStatusException; - +import com.rarchives.ripme.App; import com.rarchives.ripme.ui.RipStatusComplete; import com.rarchives.ripme.ui.RipStatusHandler; import com.rarchives.ripme.ui.RipStatusMessage; import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Utils; -import java.io.File; -import java.util.Scanner; - public abstract class AbstractRipper extends Observable implements RipperInterface, Runnable { @@ -548,7 +548,7 @@ public abstract class AbstractRipper public static AbstractRipper getRipper(URL url) throws Exception { for (Constructor constructor : getRipperConstructors("com.rarchives.ripme.ripper.rippers")) { try { - AlbumRipper ripper = (AlbumRipper) constructor.newInstance(url); // by design: can throw ClassCastException + AbstractRipper ripper = (AbstractRipper) constructor.newInstance(url); // by design: can throw ClassCastException LOGGER.debug("Found album ripper: " + ripper.getClass().getName()); return ripper; } catch (Exception e) { From a4d61e3cfdd1d9ce5aa39a0e3a50a27697cfb438 Mon Sep 17 00:00:00 2001 From: Isaaku Date: Tue, 13 Aug 2019 19:52:23 -0500 Subject: [PATCH 09/16] Fix video dimension Fix GIF downloads --- .../ripme/ripper/rippers/TwitterRipper.java | 120 +++++++----------- 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java index 7a10a23c..cc155104 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java @@ -22,8 +22,7 @@ public class TwitterRipper extends AlbumRipper { int downloadUrls = 1; - private static final String DOMAIN = "twitter.com", - HOST = "twitter"; + private static final String DOMAIN = "twitter.com", HOST = "twitter"; private static final int MAX_REQUESTS = Utils.getConfigInteger("twitter.max_requests", 10); private static final boolean RIP_RETWEETS = Utils.getConfigBoolean("twitter.rip_retweets", true); @@ -34,8 +33,7 @@ public class TwitterRipper extends AlbumRipper { private String accessToken; private enum ALBUM_TYPE { - ACCOUNT, - SEARCH + ACCOUNT, SEARCH } private ALBUM_TYPE albumType; @@ -75,13 +73,10 @@ public class TwitterRipper extends AlbumRipper { } private void getAccessToken() throws IOException { - Document doc = Http.url("https://api.twitter.com/oauth2/token") - .ignoreContentType() + Document doc = Http.url("https://api.twitter.com/oauth2/token").ignoreContentType() .header("Authorization", "Basic " + authKey) .header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") - .header("User-agent", "ripe and zipe") - .data("grant_type", "client_credentials") - .post(); + .header("User-agent", "ripe and zipe").data("grant_type", "client_credentials").post(); String body = doc.body().html().replaceAll(""", "\""); try { JSONObject json = new JSONObject(body); @@ -94,17 +89,13 @@ public class TwitterRipper extends AlbumRipper { private void checkRateLimits(String resource, String api) throws IOException { Document doc = Http.url("https://api.twitter.com/1.1/application/rate_limit_status.json?resources=" + resource) - .ignoreContentType() - .header("Authorization", "Bearer " + accessToken) + .ignoreContentType().header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") - .header("User-agent", "ripe and zipe") - .get(); + .header("User-agent", "ripe and zipe").get(); String body = doc.body().html().replaceAll(""", "\""); try { JSONObject json = new JSONObject(body); - JSONObject stats = json.getJSONObject("resources") - .getJSONObject(resource) - .getJSONObject(api); + JSONObject stats = json.getJSONObject("resources").getJSONObject(resource).getJSONObject(api); int remaining = stats.getInt("remaining"); LOGGER.info(" Twitter " + resource + " calls remaining: " + remaining); if (remaining < 20) { @@ -120,23 +111,17 @@ public class TwitterRipper extends AlbumRipper { private String getApiURL(Long maxID) { StringBuilder req = new StringBuilder(); switch (albumType) { - case ACCOUNT: - req.append("https://api.twitter.com/1.1/statuses/user_timeline.json") - .append("?screen_name=" + this.accountName) - .append("&include_entities=true") - .append("&exclude_replies=true") - .append("&trim_user=true") - .append("&count=" + 200) - .append("&tweet_mode=extended"); - break; - case SEARCH: - req.append("https://api.twitter.com/1.1/search/tweets.json") - .append("?q=" + this.searchText) - .append("&include_entities=true") - .append("&result_type=recent") - .append("&count=100") - .append("&tweet_mode=extended"); - break; + case ACCOUNT: + req.append("https://api.twitter.com/1.1/statuses/user_timeline.json") + .append("?screen_name=" + this.accountName).append("&include_entities=true") + .append("&exclude_replies=true").append("&trim_user=true").append("&count=" + 200) + .append("&tweet_mode=extended"); + break; + case SEARCH: + req.append("https://api.twitter.com/1.1/search/tweets.json").append("?q=" + this.searchText) + .append("&include_entities=true").append("&result_type=recent").append("&count=100") + .append("&tweet_mode=extended"); + break; } if (maxID > 0) { req.append("&max_id=" + Long.toString(maxID)); @@ -147,12 +132,9 @@ public class TwitterRipper extends AlbumRipper { private List getTweets(String url) throws IOException { List tweets = new ArrayList<>(); LOGGER.info(" Retrieving " + url); - Document doc = Http.url(url) - .ignoreContentType() - .header("Authorization", "Bearer " + accessToken) + Document doc = Http.url(url).ignoreContentType().header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") - .header("User-agent", "ripe and zipe") - .get(); + .header("User-agent", "ripe and zipe").get(); String body = doc.body().html().replaceAll(""", "\""); Object jsonObj = new JSONTokener(body).nextValue(); JSONArray statuses; @@ -178,7 +160,7 @@ public class TwitterRipper extends AlbumRipper { LOGGER.error("XXX Tweet doesn't have entitites"); return 0; } - + if (!RIP_RETWEETS && tweet.has("retweeted_status")) { LOGGER.info("Skipping a retweet as twitter.rip_retweet is set to false."); return 0; @@ -194,19 +176,22 @@ public class TwitterRipper extends AlbumRipper { for (int i = 0; i < medias.length(); i++) { media = (JSONObject) medias.get(i); url = media.getString("media_url"); - if (media.getString("type").equals("video")) { + if (media.getString("type").equals("video") || media.getString("type").equals("animated_gif")) { JSONArray variants = media.getJSONObject("video_info").getJSONArray("variants"); int largestBitrate = 0; String urlToDownload = null; // Loop over all the video options and find the biggest video - for (int j = 0; j < medias.length(); j++) { - JSONObject variant = (JSONObject) variants.get(i); + for (int j = 0; j < variants.length(); j++) { + JSONObject variant = (JSONObject) variants.get(j); LOGGER.info(variant); // If the video doesn't have a bitrate it's a m3u8 file we can't download if (variant.has("bitrate")) { if (variant.getInt("bitrate") > largestBitrate) { largestBitrate = variant.getInt("bitrate"); urlToDownload = variant.getString("url"); + } else if (media.getString("type").equals("animated_gif")) { + // If the type if animated_gif the bitrate doesn't matter + urlToDownload = variant.getString("url"); } } } @@ -230,7 +215,6 @@ public class TwitterRipper extends AlbumRipper { } } - return parsedCount; } @@ -243,12 +227,12 @@ public class TwitterRipper extends AlbumRipper { getAccessToken(); switch (albumType) { - case ACCOUNT: - checkRateLimits("statuses", "/statuses/user_timeline"); - break; - case SEARCH: - checkRateLimits("search", "/search/tweets"); - break; + case ACCOUNT: + checkRateLimits("statuses", "/statuses/user_timeline"); + break; + case SEARCH: + checkRateLimits("search", "/search/tweets"); + break; } Long lastMaxID = 0L; @@ -260,9 +244,7 @@ public class TwitterRipper extends AlbumRipper { break; } LOGGER.debug("Twitter response #" + (i + 1) + " Tweets:\n" + tweets); - if (tweets.size() == 1 && - lastMaxID.equals(tweets.get(0).getString("id_str")) - ) { + if (tweets.size() == 1 && lastMaxID.equals(tweets.get(0).getString("id_str"))) { LOGGER.info(" No more tweet found."); break; } @@ -299,26 +281,22 @@ public class TwitterRipper extends AlbumRipper { @Override public String getGID(URL url) throws MalformedURLException { switch (albumType) { - case ACCOUNT: - return "account_" + accountName; - case SEARCH: - StringBuilder gid = new StringBuilder(); - for (int i = 0; i < searchText.length(); i++) { - char c = searchText.charAt(i); - // Ignore URL-encoded chars - if (c == '%') { - gid.append('_'); - i += 2; - // Ignore non-alphanumeric chars - } else if ( - (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - ) { - gid.append(c); - } + case ACCOUNT: + return "account_" + accountName; + case SEARCH: + StringBuilder gid = new StringBuilder(); + for (int i = 0; i < searchText.length(); i++) { + char c = searchText.charAt(i); + // Ignore URL-encoded chars + if (c == '%') { + gid.append('_'); + i += 2; + // Ignore non-alphanumeric chars + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { + gid.append(c); } - return "search_" + gid.toString(); + } + return "search_" + gid.toString(); } throw new MalformedURLException("Could not decide type of URL (search/account): " + url); } From 606f67af0283b1176b95a3afccc3713264c8299f Mon Sep 17 00:00:00 2001 From: Isaaku Date: Tue, 13 Aug 2019 20:11:35 -0500 Subject: [PATCH 10/16] Added download.save_order to avoid prefix when disabled --- .../java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java b/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java index cc155104..b27cbc04 100644 --- a/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java +++ b/src/main/java/com/rarchives/ripme/ripper/rippers/TwitterRipper.java @@ -219,7 +219,7 @@ public class TwitterRipper extends AlbumRipper { } public String getPrefix(int index) { - return String.format("%03d_", index); + return Utils.getConfigBoolean("download.save_order", true) ? String.format("%03d_", index) : ""; } @Override From c11d34e397c0524cf0ac221a49fb23514b40450f Mon Sep 17 00:00:00 2001 From: Isaaku Date: Wed, 14 Aug 2019 13:00:29 -0500 Subject: [PATCH 11/16] Change the logic of locate to Utils Update use of ResourceBundle Added queue properties missing in LabelBundle Delete content of LabelsBundle_en_US.properties since the default language is English --- .../ripme/ripper/DownloadFileThread.java | 118 ++-- .../com/rarchives/ripme/ui/MainWindow.java | 548 ++++++++++-------- .../java/com/rarchives/ripme/utils/Utils.java | 17 + src/main/resources/LabelsBundle.properties | 7 +- .../resources/LabelsBundle_ar_AR.properties | 2 +- .../resources/LabelsBundle_de_DE.properties | 2 +- .../resources/LabelsBundle_en_US.properties | 58 +- .../resources/LabelsBundle_es_ES.properties | 7 +- .../resources/LabelsBundle_fi_FI.properties | 2 +- .../resources/LabelsBundle_fr_CH.properties | 2 +- .../resources/LabelsBundle_in_ID.properties | 2 +- .../resources/LabelsBundle_it_IT.properties | 8 +- .../resources/LabelsBundle_kr_KR.properties | 2 +- .../resources/LabelsBundle_nl_NL.properties | 2 +- .../resources/LabelsBundle_pl_PL.properties | 2 +- .../LabelsBundle_porrisavvo_FI.properties | 2 +- .../resources/LabelsBundle_pt_BR.properties | 2 +- .../resources/LabelsBundle_pt_PT.properties | 2 +- .../resources/LabelsBundle_ru_RU.properties | 2 +- 19 files changed, 424 insertions(+), 363 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java b/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java index 3b1e7c16..3613273e 100644 --- a/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java +++ b/src/main/java/com/rarchives/ripme/ripper/DownloadFileThread.java @@ -20,17 +20,14 @@ import com.rarchives.ripme.ui.RipStatusMessage.STATUS; import com.rarchives.ripme.utils.Utils; /** - * Thread for downloading files. - * Includes retry logic, observer notifications, and other goodies. + * Thread for downloading files. Includes retry logic, observer notifications, + * and other goodies. */ class DownloadFileThread extends Thread { - - private ResourceBundle rb = MainWindow.rb; - private static final Logger logger = Logger.getLogger(DownloadFileThread.class); private String referrer = ""; - private Map cookies = new HashMap<>(); + private Map cookies = new HashMap<>(); private URL url; private File saveAs; @@ -55,18 +52,19 @@ class DownloadFileThread extends Thread { public void setReferrer(String referrer) { this.referrer = referrer; } - public void setCookies(Map cookies) { + + public void setCookies(Map cookies) { this.cookies = cookies; } - /** - * Attempts to download the file. Retries as needed. - * Notifies observers upon completion/error/warn. + * Attempts to download the file. Retries as needed. Notifies observers upon + * completion/error/warn. */ public void run() { // 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; int bytesTotal = 0; int bytesDownloaded = 0; @@ -76,16 +74,18 @@ class DownloadFileThread extends Thread { try { observer.stopCheck(); } catch (IOException e) { - observer.downloadErrored(url, rb.getString("download.interrupted")); + observer.downloadErrored(url, Utils.getLocalizedString("download.interrupted")); return; } - if (saveAs.exists() && !observer.tryResumeDownload() && !getFileExtFromMIME || - Utils.fuzzyExists(new File(saveAs.getParent()), saveAs.getName()) && getFileExtFromMIME && !observer.tryResumeDownload()) { + if (saveAs.exists() && !observer.tryResumeDownload() && !getFileExtFromMIME + || Utils.fuzzyExists(new File(saveAs.getParent()), saveAs.getName()) && getFileExtFromMIME + && !observer.tryResumeDownload()) { if (Utils.getConfigBoolean("file.overwrite", false)) { - logger.info("[!] " + rb.getString("deleting.existing.file") + prettySaveAs); + logger.info("[!] " + Utils.getLocalizedString("deleting.existing.file") + prettySaveAs); saveAs.delete(); } 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); return; } @@ -95,7 +95,8 @@ class DownloadFileThread extends Thread { int tries = 0; // Number of attempts to download do { tries += 1; - InputStream bis = null; OutputStream fos = null; + InputStream bis = null; + OutputStream fos = null; try { logger.info(" Downloading file: " + urlToDownload + (tries > 0 ? " Retry #" + tries : "")); observer.sendUpdate(STATUS.DOWNLOAD_STARTED, url.toExternalForm()); @@ -104,16 +105,16 @@ class DownloadFileThread extends Thread { HttpURLConnection huc; if (this.url.toString().startsWith("https")) { huc = (HttpsURLConnection) urlToDownload.openConnection(); - } - else { + } else { huc = (HttpURLConnection) urlToDownload.openConnection(); } 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. huc.setConnectTimeout(TIMEOUT); huc.setReadTimeout(TIMEOUT); - huc.setRequestProperty("accept", "*/*"); + huc.setRequestProperty("accept", "*/*"); if (!referrer.equals("")) { huc.setRequestProperty("Referer", referrer); // Sic } @@ -131,17 +132,18 @@ class DownloadFileThread extends Thread { huc.setRequestProperty("Range", "bytes=" + fileSize + "-"); } } - logger.debug(rb.getString("request.properties") + ": " + huc.getRequestProperties()); + logger.debug(Utils.getLocalizedString("request.properties") + ": " + huc.getRequestProperties()); huc.connect(); int statusCode = huc.getResponseCode(); logger.debug("Status code: " + statusCode); // If the server doesn't allow resuming downloads error out 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 - throw new IOException(rb.getString("server.doesnt.support.resuming.downloads")); + // TODO find a better way to handle servers that don't support resuming + // 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) { // Don't increment retries on the first redirect tries--; @@ -153,14 +155,17 @@ class DownloadFileThread extends Thread { throw new IOException("Redirect status code " + statusCode + " - redirect to " + location); } if (statusCode / 100 == 4) { // 4xx errors - logger.error("[!] " + rb.getString("nonretriable.status.code") + " " + statusCode + " while downloading from " + url); - observer.downloadErrored(url, rb.getString("nonretriable.status.code") + " " + statusCode + " while downloading " + url.toExternalForm()); + logger.error("[!] " + Utils.getLocalizedString("nonretriable.status.code") + " " + statusCode + + " while downloading from " + url); + observer.downloadErrored(url, Utils.getLocalizedString("nonretriable.status.code") + " " + + statusCode + " while downloading " + url.toExternalForm()); return; // Not retriable, drop out. } 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 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")) { // Imgur image with 503 bytes is "404" @@ -169,7 +174,8 @@ class DownloadFileThread extends Thread { 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()) { bytesTotal = huc.getContentLength(); observer.setBytesTotal(bytesTotal); @@ -190,14 +196,15 @@ class DownloadFileThread extends Thread { logger.error("Was unable to get content type from stream"); // Try to get the file type from the magic number byte[] magicBytes = new byte[8]; - bis.read(magicBytes,0, 5); + bis.read(magicBytes, 0, 5); bis.reset(); fileExt = Utils.getEXTFromMagic(magicBytes); if (fileExt != null) { saveAs = new File(saveAs.toString() + "." + fileExt); } else { - logger.error(rb.getString("was.unable.to.get.content.type.using.magic.number")); - logger.error(rb.getString("magic.number.was") + ": " + Arrays.toString(magicBytes)); + logger.error(Utils.getLocalizedString("was.unable.to.get.content.type.using.magic.number")); + logger.error( + Utils.getLocalizedString("magic.number.was") + ": " + Arrays.toString(magicBytes)); } } } @@ -210,21 +217,26 @@ class DownloadFileThread extends Thread { } catch (FileNotFoundException e) { // We do this because some filesystems have a max name length 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"); 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]; // The max limit for filenames on Linux with Ext3/4 is 255 bytes logger.info(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 saveAs = new File(saveAs.getParentFile().getAbsolutePath() + File.separator + filename); fos = new FileOutputStream(saveAs); } 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 - fos = new FileOutputStream(Utils.shortenSaveAsWindows(saveAs.getParentFile().getPath(), saveAs.getName())); + // This if is for when the file path has gone above 260 chars which windows does + // not allow + fos = new FileOutputStream( + Utils.shortenSaveAsWindows(saveAs.getParentFile().getPath(), saveAs.getName())); } } } @@ -239,7 +251,7 @@ class DownloadFileThread extends Thread { try { observer.stopCheck(); } catch (IOException e) { - observer.downloadErrored(url, rb.getString("download.interrupted")); + observer.downloadErrored(url, Utils.getLocalizedString("download.interrupted")); return; } fos.write(data, 0, bytesRead); @@ -259,27 +271,37 @@ class DownloadFileThread extends Thread { // Download failed, break out of loop break; } 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); 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; } } catch (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 { // Close any open streams try { - if (bis != null) { bis.close(); } - } catch (IOException e) { } + if (bis != null) { + bis.close(); + } + } catch (IOException e) { + } try { - if (fos != null) { fos.close(); } - } catch (IOException e) { } + if (fos != null) { + fos.close(); + } + } catch (IOException e) { + } } if (tries > this.retries) { - logger.error("[!] " + rb.getString ("exceeded.maximum.retries") + " (" + this.retries + ") for URL " + url); - observer.downloadErrored(url, rb.getString("failed.to.download") + " " + url.toExternalForm()); + logger.error("[!] " + Utils.getLocalizedString("exceeded.maximum.retries") + " (" + this.retries + + ") for URL " + url); + observer.downloadErrored(url, + Utils.getLocalizedString("failed.to.download") + " " + url.toExternalForm()); return; } } while (true); diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java index e97e915a..2d69542c 100644 --- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java +++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java @@ -71,8 +71,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { private static JFrame mainFrame; private static JTextField ripTextfield; - private static JButton ripButton, - stopButton; + private static JButton ripButton, stopButton; private static JLabel statusLabel; private static JButton openButton; @@ -93,14 +92,13 @@ public final class MainWindow implements Runnable, RipStatusHandler { private static JPanel historyPanel; private static JTable historyTable; private static AbstractTableModel historyTableModel; - private static JButton historyButtonRemove, - historyButtonClear, - historyButtonRerip; + private static JButton historyButtonRemove, historyButtonClear, historyButtonRerip; // Queue public static JButton optionQueue; private static JPanel queuePanel; - private static DefaultListModel queueListModel; + private static DefaultListModel queueListModel; + private static QueueMenuMouseListener queueMenuMouseListener; // Configuration private static JButton optionConfiguration; @@ -141,34 +139,23 @@ public final class MainWindow implements Runnable, RipStatusHandler { private static AbstractRipper ripper; - public static ResourceBundle rb = Utils.getResourceBundle(null); - // All the langs ripme has been translated into - 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 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() { - if (queueListModel.size() > 0) { - optionQueue.setText(rb.getString("Queue") + " (" + queueListModel.size() + ")"); - } else { - optionQueue.setText(rb.getString("Queue")); - } + private void updateQueue(DefaultListModel model) { + if (model == null) + model = queueListModel; + + Utils.setConfigList("Queue", (Enumeration) model.elements()); + + MainWindow.optionQueue.setText(String.format("%s%s", Utils.getLocalizedString("queue"), + model.size() == 0 ? "" : "(" + model.size() + ")")); } + private void updateQueue() { + updateQueue(null); + } private static void addCheckboxListener(JCheckBox checkBox, String configString) { checkBox.addActionListener(arg0 -> { @@ -185,7 +172,6 @@ public final class MainWindow implements Runnable, RipStatusHandler { return checkbox; } - public static void addUrlToQueue(String url) { queueListModel.addElement(url); } @@ -276,29 +262,32 @@ public final class MainWindow implements Runnable, RipStatusHandler { } private boolean isCollapsed() { - return (!logPanel.isVisible() && - !historyPanel.isVisible() && - !queuePanel.isVisible() && - !configurationPanel.isVisible() - ); + return (!logPanel.isVisible() && !historyPanel.isVisible() && !queuePanel.isVisible() + && !configurationPanel.isVisible()); } private void createUI(Container pane) { - //If creating the tray icon fails, ignore it. + // If creating the tray icon fails, ignore it. try { setupTrayIcon(); - } catch (Exception e) { } + } catch (Exception e) { + } EmptyBorder emptyBorder = new EmptyBorder(5, 5, 5, 5); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.weightx = 1; gbc.ipadx = 2; gbc.gridx = 0; - gbc.weighty = 0; gbc.ipady = 2; gbc.gridy = 0; + gbc.weightx = 1; + gbc.ipadx = 2; + gbc.gridx = 0; + gbc.weighty = 0; + gbc.ipady = 2; + gbc.gridy = 0; gbc.anchor = GridBagConstraints.PAGE_START; try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) { + } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException + | IllegalAccessException e) { LOGGER.error("[!] Exception setting system theme:", e); } @@ -311,31 +300,38 @@ public final class MainWindow implements Runnable, RipStatusHandler { try { Image stopIcon = ImageIO.read(getClass().getClassLoader().getResource("stop.png")); stopButton.setIcon(new ImageIcon(stopIcon)); - } catch (Exception ignored) { } + } catch (Exception ignored) { + } JPanel ripPanel = new JPanel(new GridBagLayout()); ripPanel.setBorder(emptyBorder); gbc.fill = GridBagConstraints.BOTH; 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.weighty = 1; - gbc.gridx = 1; ripPanel.add(ripTextfield, gbc); + gbc.gridx = 1; + ripPanel.add(ripTextfield, gbc); gbc.weighty = 0; gbc.weightx = 0; - gbc.gridx = 2; ripPanel.add(ripButton, gbc); - gbc.gridx = 3; ripPanel.add(stopButton, gbc); + gbc.gridx = 2; + ripPanel.add(ripButton, gbc); + gbc.gridx = 3; + ripPanel.add(stopButton, gbc); gbc.weightx = 1; - statusLabel = new JLabel(rb.getString("inactive")); + statusLabel = new JLabel(Utils.getLocalizedString("inactive")); statusLabel.setHorizontalAlignment(JLabel.CENTER); openButton = new JButton(); openButton.setVisible(false); JPanel statusPanel = new JPanel(new GridBagLayout()); statusPanel.setBorder(emptyBorder); - gbc.gridx = 0; statusPanel.add(statusLabel, gbc); - gbc.gridy = 1; statusPanel.add(openButton, gbc); + gbc.gridx = 0; + statusPanel.add(statusLabel, gbc); + gbc.gridy = 1; + statusPanel.add(openButton, gbc); gbc.gridy = 0; JPanel progressPanel = new JPanel(new GridBagLayout()); @@ -345,10 +341,10 @@ public final class MainWindow implements Runnable, RipStatusHandler { JPanel optionsPanel = new JPanel(new GridBagLayout()); optionsPanel.setBorder(emptyBorder); - 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 = new JButton(Utils.getLocalizedString("Log")); + optionHistory = new JButton(Utils.getLocalizedString("History")); + optionQueue = new JButton(Utils.getLocalizedString("queue")); + optionConfiguration = new JButton(Utils.getLocalizedString("Configuration")); optionLog.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionHistory.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); optionQueue.setFont(optionLog.getFont().deriveFont(Font.PLAIN)); @@ -363,11 +359,16 @@ public final class MainWindow implements Runnable, RipStatusHandler { optionQueue.setIcon(new ImageIcon(icon)); icon = ImageIO.read(getClass().getClassLoader().getResource("gear.png")); optionConfiguration.setIcon(new ImageIcon(icon)); - } catch (Exception e) { } - gbc.gridx = 0; optionsPanel.add(optionLog, gbc); - gbc.gridx = 1; optionsPanel.add(optionHistory, gbc); - gbc.gridx = 2; optionsPanel.add(optionQueue, gbc); - gbc.gridx = 3; optionsPanel.add(optionConfiguration, gbc); + } catch (Exception e) { + } + gbc.gridx = 0; + optionsPanel.add(optionLog, 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.setBorder(emptyBorder); @@ -389,30 +390,37 @@ public final class MainWindow implements Runnable, RipStatusHandler { historyPanel.setPreferredSize(new Dimension(300, 250)); historyTableModel = new AbstractTableModel() { private static final long serialVersionUID = 1L; + @Override public String getColumnName(int col) { return HISTORY.getColumnName(col); } + @Override public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } + @Override public Object getValueAt(int row, int col) { return HISTORY.getValueAt(row, col); } + @Override public int getRowCount() { return HISTORY.toList().size(); } + @Override public int getColumnCount() { return HISTORY.getColumnCount(); } + @Override public boolean isCellEditable(int row, int col) { return (col == 0 || col == 4); } + @Override public void setValueAt(Object value, int row, int col) { if (col == 4) { @@ -440,9 +448,9 @@ public final class MainWindow implements Runnable, RipStatusHandler { historyTable.getColumnModel().getColumn(i).setPreferredWidth(width); } JScrollPane historyTableScrollPane = new JScrollPane(historyTable); - historyButtonRemove = new JButton(rb.getString("remove")); - historyButtonClear = new JButton(rb.getString("clear")); - historyButtonRerip = new JButton(rb.getString("re-rip.checked")); + historyButtonRemove = new JButton(Utils.getLocalizedString("remove")); + historyButtonClear = new JButton(Utils.getLocalizedString("clear")); + historyButtonRerip = new JButton(Utils.getLocalizedString("re-rip.checked")); gbc.gridx = 0; // History List Panel JPanel historyTablePanel = new JPanel(new GridBagLayout()); @@ -456,10 +464,14 @@ public final class MainWindow implements Runnable, RipStatusHandler { JPanel historyButtonPanel = new JPanel(new GridBagLayout()); historyButtonPanel.setPreferredSize(new Dimension(300, 10)); historyButtonPanel.setBorder(emptyBorder); - gbc.gridx = 0; historyButtonPanel.add(historyButtonRemove, gbc); - gbc.gridx = 1; historyButtonPanel.add(historyButtonClear, gbc); - gbc.gridx = 2; historyButtonPanel.add(historyButtonRerip, gbc); - gbc.gridy = 1; gbc.gridx = 0; + gbc.gridx = 0; + historyButtonPanel.add(historyButtonRemove, gbc); + gbc.gridx = 1; + historyButtonPanel.add(historyButtonClear, gbc); + gbc.gridx = 2; + historyButtonPanel.add(historyButtonRerip, gbc); + gbc.gridy = 1; + gbc.gridx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.HORIZONTAL; historyPanel.add(historyButtonPanel, gbc); @@ -468,17 +480,17 @@ public final class MainWindow implements Runnable, RipStatusHandler { queuePanel.setBorder(emptyBorder); queuePanel.setVisible(false); queuePanel.setPreferredSize(new Dimension(300, 250)); - queueListModel = new DefaultListModel(); + queueListModel = new DefaultListModel(); JList queueList = new JList(queueListModel); queueList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - queueList.addMouseListener(new QueueMenuMouseListener()); - JScrollPane queueListScroll = new JScrollPane(queueList, - JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + queueList.addMouseListener(queueMenuMouseListener = new QueueMenuMouseListener((model) -> updateQueue(model))); + JScrollPane queueListScroll = new JScrollPane(queueList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); for (String item : Utils.getConfigList("queue")) { queueListModel.addElement(item); } - updateQueueLabel(); + updateQueue(); + gbc.gridx = 0; JPanel queueListPanel = new JPanel(new GridBagLayout()); gbc.fill = GridBagConstraints.BOTH; @@ -493,32 +505,42 @@ public final class MainWindow implements Runnable, RipStatusHandler { configurationPanel.setBorder(emptyBorder); configurationPanel.setVisible(false); // TODO Configuration components - configUpdateButton = new JButton(rb.getString("check.for.updates")); - configUpdateLabel = new JLabel( rb.getString("current.version") + ": " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT); - configThreadsLabel = new JLabel(rb.getString("max.download.threads") + ":", JLabel.RIGHT); - configTimeoutLabel = new JLabel(rb.getString("timeout.mill"), JLabel.RIGHT); - configRetriesLabel = new JLabel(rb.getString("retry.download.count"), JLabel.RIGHT); + configUpdateButton = new JButton(Utils.getLocalizedString("check.for.updates")); + configUpdateLabel = new JLabel( + Utils.getLocalizedString("current.version") + ": " + UpdateUtils.getThisJarVersion(), JLabel.RIGHT); + configThreadsLabel = new JLabel(Utils.getLocalizedString("max.download.threads") + ":", 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))); configTimeoutText = new JTextField(Integer.toString(Utils.getConfigInteger("download.timeout", 60000))); configRetriesText = new JTextField(Integer.toString(Utils.getConfigInteger("download.retries", 3))); - 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); - configUrlFileChooserButton = new JButton(rb.getString("download.url.list")); + configOverwriteCheckbox = addNewCheckbox(Utils.getLocalizedString("overwrite.existing.files"), "file.overwrite", + false); + configAutoupdateCheckbox = addNewCheckbox(Utils.getLocalizedString("auto.update"), "auto.update", true); + configPlaySound = addNewCheckbox(Utils.getLocalizedString("sound.when.rip.completes"), "play.sound", false); + configShowPopup = addNewCheckbox(Utils.getLocalizedString("notification.when.rip.starts"), + "download.show_popup", false); + configSaveOrderCheckbox = addNewCheckbox(Utils.getLocalizedString("preserve.order"), "download.save_order", + true); + configSaveLogs = addNewCheckbox(Utils.getLocalizedString("save.logs"), "log.save", false); + configSaveURLsOnly = addNewCheckbox(Utils.getLocalizedString("save.urls.only"), "urls_only.save", false); + configSaveAlbumTitles = addNewCheckbox(Utils.getLocalizedString("save.album.titles"), "album_titles.save", + true); + configClipboardAutorip = addNewCheckbox(Utils.getLocalizedString("autorip.from.clipboard"), "clipboard.autorip", + 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<>( + new String[] { "Log level: Error", "Log level: Warn", "Log level: Info", "Log level: Debug" }); configSelectLangComboBox = new JComboBox<>(supportedLanges); - configSelectLangComboBox.setSelectedItem(rb.getLocale().toString()); + configSelectLangComboBox.setSelectedItem(Utils.getLanguage()); configLogLevelCombobox.setSelectedItem(Utils.getConfigString("log.level", "Log level: Debug")); setLogLevel(configLogLevelCombobox.getSelectedItem().toString()); configSaveDirLabel = new JLabel(); @@ -527,10 +549,11 @@ public final class MainWindow implements Runnable, RipStatusHandler { configSaveDirLabel.setText(workingDir); configSaveDirLabel.setForeground(Color.BLUE); configSaveDirLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); - } catch (Exception e) { } + } catch (Exception e) { + } configSaveDirLabel.setToolTipText(configSaveDirLabel.getText()); 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, 1, configAutoupdateCheckbox, configLogLevelCombobox); @@ -546,84 +569,114 @@ public final class MainWindow implements Runnable, RipStatusHandler { addItemToConfigGridBagConstraints(gbc, 11, configSelectLangComboBox, configUrlFileChooserButton); addItemToConfigGridBagConstraints(gbc, 12, configSaveDirLabel, configSaveDirButton); - - - emptyPanel = new JPanel(); emptyPanel.setPreferredSize(new Dimension(0, 0)); emptyPanel.setSize(0, 0); gbc.anchor = GridBagConstraints.PAGE_START; - gbc.gridy = 0; pane.add(ripPanel, gbc); - gbc.gridy = 1; pane.add(statusPanel, gbc); - gbc.gridy = 2; pane.add(progressPanel, gbc); - gbc.gridy = 3; pane.add(optionsPanel, gbc); + gbc.gridy = 0; + pane.add(ripPanel, gbc); + gbc.gridy = 1; + pane.add(statusPanel, gbc); + gbc.gridy = 2; + pane.add(progressPanel, gbc); + gbc.gridy = 3; + pane.add(optionsPanel, gbc); gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; - gbc.gridy = 4; pane.add(logPanel, gbc); - gbc.gridy = 5; pane.add(historyPanel, gbc); - gbc.gridy = 5; pane.add(queuePanel, gbc); - gbc.gridy = 5; pane.add(configurationPanel, gbc); - gbc.gridy = 5; pane.add(emptyPanel, gbc); + gbc.gridy = 4; + pane.add(logPanel, gbc); + gbc.gridy = 5; + pane.add(historyPanel, 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.fill = GridBagConstraints.HORIZONTAL; } - private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JLabel thing1ToAdd, JButton thing2ToAdd ) { - 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, + JButton thing2ToAdd) { + 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 ) { - 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) { + 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 ) { - 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) { + 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 ) { - 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) { + 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 ) { - 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) { + 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 ) { - gbc.gridy = gbcYValue; gbc.gridx = 0; configurationPanel.add(thing1ToAdd, gbc); + private void addItemToConfigGridBagConstraints(GridBagConstraints gbc, int gbcYValue, JComboBox thing1ToAdd) { + gbc.gridy = gbcYValue; + gbc.gridx = 0; + configurationPanel.add(thing1ToAdd, gbc); } private void changeLocale() { - statusLabel.setText(rb.getString("inactive")); - configUpdateButton.setText(rb.getString("check.for.updates")); - configUpdateLabel.setText(rb.getString("current.version") + ": " + UpdateUtils.getThisJarVersion()); - configThreadsLabel.setText(rb.getString("max.download.threads")); - configTimeoutLabel.setText(rb.getString("timeout.mill")); - configRetriesLabel.setText(rb.getString("retry.download.count")); - configOverwriteCheckbox.setText(rb.getString("overwrite.existing.files")); - configAutoupdateCheckbox.setText(rb.getString("auto.update")); - configPlaySound.setText(rb.getString("sound.when.rip.completes")); - configShowPopup.setText(rb.getString("notification.when.rip.starts")); - configSaveOrderCheckbox.setText(rb.getString("preserve.order")); - configSaveLogs.setText(rb.getString("save.logs")); - configSaveURLsOnly.setText(rb.getString("save.urls.only")); - configSaveAlbumTitles.setText(rb.getString("save.album.titles")); - configClipboardAutorip.setText(rb.getString("autorip.from.clipboard")); - configSaveDescriptions.setText(rb.getString("save.descriptions")); - configUrlFileChooserButton.setText(rb.getString("download.url.list")); - configSaveDirButton.setText(rb.getString("select.save.dir") + "..."); - configPreferMp4.setText(rb.getString("prefer.mp4.over.gif")); - configWindowPosition.setText(rb.getString("restore.window.position")); - configURLHistoryCheckbox.setText(rb.getString("remember.url.history")); - optionLog.setText(rb.getString("Log")); - optionHistory.setText(rb.getString("History")); - optionQueue.setText(rb.getString("Queue")); - optionConfiguration.setText(rb.getString("Configuration")); + statusLabel.setText(Utils.getLocalizedString("inactive")); + configUpdateButton.setText(Utils.getLocalizedString("check.for.updates")); + configUpdateLabel.setText(Utils.getLocalizedString("current.version") + ": " + UpdateUtils.getThisJarVersion()); + configThreadsLabel.setText(Utils.getLocalizedString("max.download.threads")); + configTimeoutLabel.setText(Utils.getLocalizedString("timeout.mill")); + configRetriesLabel.setText(Utils.getLocalizedString("retry.download.count")); + configOverwriteCheckbox.setText(Utils.getLocalizedString("overwrite.existing.files")); + configAutoupdateCheckbox.setText(Utils.getLocalizedString("auto.update")); + configPlaySound.setText(Utils.getLocalizedString("sound.when.rip.completes")); + configShowPopup.setText(Utils.getLocalizedString("notification.when.rip.starts")); + configSaveOrderCheckbox.setText(Utils.getLocalizedString("preserve.order")); + configSaveLogs.setText(Utils.getLocalizedString("save.logs")); + configSaveURLsOnly.setText(Utils.getLocalizedString("save.urls.only")); + configSaveAlbumTitles.setText(Utils.getLocalizedString("save.album.titles")); + configClipboardAutorip.setText(Utils.getLocalizedString("autorip.from.clipboard")); + configSaveDescriptions.setText(Utils.getLocalizedString("save.descriptions")); + configUrlFileChooserButton.setText(Utils.getLocalizedString("download.url.list")); + configSaveDirButton.setText(Utils.getLocalizedString("select.save.dir") + "..."); + configPreferMp4.setText(Utils.getLocalizedString("prefer.mp4.over.gif")); + configWindowPosition.setText(Utils.getLocalizedString("restore.window.position")); + configURLHistoryCheckbox.setText(Utils.getLocalizedString("remember.url.history")); + optionLog.setText(Utils.getLocalizedString("Log")); + optionHistory.setText(Utils.getLocalizedString("History")); + optionQueue.setText(Utils.getLocalizedString("queue")); + optionConfiguration.setText(Utils.getLocalizedString("Configuration")); + + queueMenuMouseListener.updateUI(); } private void setupHandlers() { @@ -634,14 +687,17 @@ public final class MainWindow implements Runnable, RipStatusHandler { public void removeUpdate(DocumentEvent e) { update(); } + @Override public void insertUpdate(DocumentEvent e) { update(); } + @Override public void changedUpdate(DocumentEvent e) { update(); } + private void update() { try { String urlText = ripTextfield.getText().trim(); @@ -668,7 +724,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { statusProgress.setVisible(false); pack(); statusProgress.setValue(0); - status("Ripping interrupted"); + status(Utils.getLocalizedString("ripping.interrupted")); appendLog("Ripper interrupted", Color.RED); } }); @@ -744,7 +800,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { } try { historyTableModel.fireTableDataChanged(); - } catch (Exception e) { } + } catch (Exception e) { + } saveHistory(); }); historyButtonClear.addActionListener(event -> { @@ -778,8 +835,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { } saveHistory(); }); - } - else { + } else { Utils.clearURLHistory(); HISTORY.clear(); try { @@ -793,10 +849,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { // Re-rip all history historyButtonRerip.addActionListener(event -> { if (HISTORY.isEmpty()) { - JOptionPane.showMessageDialog(null, - "There are no history entries to re-rip. Rip some albums first", - "RipMe Error", - JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "There are no history entries to re-rip. Rip some albums first", + "RipMe Error", JOptionPane.ERROR_MESSAGE); return; } int added = 0; @@ -807,11 +861,9 @@ public final class MainWindow implements Runnable, RipStatusHandler { } } if (added == 0) { - JOptionPane.showMessageDialog(null, - "No history entries have been 'Checked'\n" + - "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); + JOptionPane.showMessageDialog(null, "No history entries have been 'Checked'\n" + + "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 -> { @@ -824,7 +876,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { }); configSelectLangComboBox.addActionListener(arg0 -> { String level = ((JComboBox) arg0.getSource()).getSelectedItem().toString(); - rb = Utils.getResourceBundle(level); + Utils.setLanguage(level); changeLocale(); }); configSaveDirLabel.addMouseListener(new MouseAdapter() { @@ -834,7 +886,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { Desktop desktop = Desktop.getDesktop(); try { desktop.open(file); - } catch (Exception e1) { } + } catch (Exception e1) { + } } }); configSaveDirButton.addActionListener(arg0 -> { @@ -882,11 +935,10 @@ public final class MainWindow implements Runnable, RipStatusHandler { } } - - } catch(IOException e) { - LOGGER.error("Error reading file " + e.getMessage()); - } - }); + } catch (IOException e) { + LOGGER.error("Error reading file " + e.getMessage()); + } + }); addCheckboxListener(configSaveOrderCheckbox, "download.save_order"); addCheckboxListener(configOverwriteCheckbox, "file.overwrite"); addCheckboxListener(configSaveLogs, "log.save"); @@ -896,7 +948,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { addCheckboxListener(configSaveDescriptions, "descriptions.save"); addCheckboxListener(configPreferMp4, "prefer.mp4"); addCheckboxListener(configWindowPosition, "window.position"); - + configClipboardAutorip.addActionListener(arg0 -> { Utils.setConfigBoolean("clipboard.autorip", configClipboardAutorip.isSelected()); ClipboardUtils.setClipboardAutoRip(configClipboardAutorip.isSelected()); @@ -907,15 +959,20 @@ public final class MainWindow implements Runnable, RipStatusHandler { queueListModel.addListDataListener(new ListDataListener() { @Override public void intervalAdded(ListDataEvent arg0) { - updateQueueLabel(); + updateQueue(); + if (!isRipping) { ripNextAlbum(); } } + @Override - public void contentsChanged(ListDataEvent arg0) { } + public void contentsChanged(ListDataEvent arg0) { + } + @Override - public void intervalRemoved(ListDataEvent arg0) { } + public void intervalRemoved(ListDataEvent arg0) { + } }); } @@ -923,26 +980,26 @@ public final class MainWindow implements Runnable, RipStatusHandler { Level newLevel = Level.ERROR; level = level.substring(level.lastIndexOf(' ') + 1); switch (level) { - case "Debug": - newLevel = Level.DEBUG; - break; - case "Info": - newLevel = Level.INFO; - break; - case "Warn": - newLevel = Level.WARN; - break; - case "Error": - newLevel = Level.ERROR; - break; + case "Debug": + newLevel = Level.DEBUG; + break; + case "Info": + newLevel = Level.INFO; + break; + case "Warn": + newLevel = Level.WARN; + break; + case "Error": + newLevel = Level.ERROR; + break; } Logger.getRootLogger().setLevel(newLevel); LOGGER.setLevel(newLevel); - ConsoleAppender ca = (ConsoleAppender)Logger.getRootLogger().getAppender("stdout"); + ConsoleAppender ca = (ConsoleAppender) Logger.getRootLogger().getAppender("stdout"); if (ca != null) { ca.setThreshold(newLevel); } - FileAppender fa = (FileAppender)Logger.getRootLogger().getAppender("FILE"); + FileAppender fa = (FileAppender) Logger.getRootLogger().getAppender("FILE"); if (fa != null) { fa.setThreshold(newLevel); } @@ -951,13 +1008,24 @@ public final class MainWindow implements Runnable, RipStatusHandler { private void setupTrayIcon() { mainFrame.addWindowListener(new WindowAdapter() { @Override - public void windowActivated(WindowEvent e) { trayMenuMain.setLabel("Hide"); } + public void windowActivated(WindowEvent e) { + trayMenuMain.setLabel("Hide"); + } + @Override - public void windowDeactivated(WindowEvent e) { trayMenuMain.setLabel("Show"); } + public void windowDeactivated(WindowEvent e) { + trayMenuMain.setLabel("Show"); + } + @Override - public void windowDeiconified(WindowEvent e) { trayMenuMain.setLabel("Hide"); } + public void windowDeiconified(WindowEvent e) { + trayMenuMain.setLabel("Hide"); + } + @Override - public void windowIconified(WindowEvent e) { trayMenuMain.setLabel("Show"); } + public void windowIconified(WindowEvent e) { + trayMenuMain.setLabel("Show"); + } }); PopupMenu trayMenu = new PopupMenu(); trayMenuMain = new MenuItem("Hide"); @@ -965,9 +1033,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { MenuItem trayMenuAbout = new MenuItem("About " + mainFrame.getTitle()); trayMenuAbout.addActionListener(arg0 -> { StringBuilder about = new StringBuilder(); - about.append("

") - .append(mainFrame.getTitle()) - .append("

"); + about.append("

").append(mainFrame.getTitle()).append("

"); about.append("Download albums from various websites:"); try { List rippers = Utils.getListOfAlbumRippers(); @@ -982,8 +1048,9 @@ public final class MainWindow implements Runnable, RipStatusHandler { about.append(""); } about.append(""); - } catch (Exception e) { } - about.append("
And download videos from video sites:"); + } catch (Exception e) { + } + about.append("
And download videos from video sites:"); try { List rippers = Utils.getListOfVideoRippers(); about.append("
    "); @@ -997,16 +1064,13 @@ public final class MainWindow implements Runnable, RipStatusHandler { about.append(""); } about.append("
"); - } catch (Exception e) { } + } catch (Exception e) { + } about.append("Do you want to visit the project homepage on Github?"); about.append(""); - int response = JOptionPane.showConfirmDialog(null, - about.toString(), - mainFrame.getTitle(), - JOptionPane.YES_NO_OPTION, - JOptionPane.PLAIN_MESSAGE, - new ImageIcon(mainIcon)); + int response = JOptionPane.showConfirmDialog(null, about.toString(), mainFrame.getTitle(), + JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon(mainIcon)); if (response == JOptionPane.YES_OPTION) { try { Desktop.getDesktop().browse(URI.create("http://github.com/ripmeapp/ripme")); @@ -1047,15 +1111,14 @@ public final class MainWindow implements Runnable, RipStatusHandler { } }); } 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(); } } private void toggleTrayClick() { - if (mainFrame.getExtendedState() == JFrame.ICONIFIED - || !mainFrame.isActive() - || !mainFrame.isVisible()) { + if (mainFrame.getExtendedState() == JFrame.ICONIFIED || !mainFrame.isActive() || !mainFrame.isVisible()) { mainFrame.setVisible(true); mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(false); @@ -1069,7 +1132,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { /** * 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 */ private void appendLog(final String text, final Color color) { @@ -1080,7 +1143,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { synchronized (this) { sd.insertString(sd.getLength(), text + "\n", sas); } - } catch (BadLocationException e) { } + } catch (BadLocationException e) { + } logText.setCaretPosition(sd.getLength()); } @@ -1088,7 +1152,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { /** * 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 */ public void displayAndLogError(String line, Color color) { @@ -1101,25 +1165,25 @@ public final class MainWindow implements Runnable, RipStatusHandler { HISTORY.clear(); if (historyFile.exists()) { try { - LOGGER.info(rb.getString("loading.history.from") + " " + historyFile.getCanonicalPath()); + LOGGER.info(Utils.getLocalizedString("loading.history.from") + " " + historyFile.getCanonicalPath()); HISTORY.fromFile(historyFile.getCanonicalPath()); } catch (IOException e) { LOGGER.error("Failed to load history from file " + historyFile, e); JOptionPane.showMessageDialog(null, - "RipMe failed to load the history file at " + historyFile.getAbsolutePath() + "\n\n" + - "Error: " + e.getMessage() + "\n\n" + - "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); + "RipMe failed to load the history file at " + historyFile.getAbsolutePath() + "\n\n" + "Error: " + + e.getMessage() + "\n\n" + + "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 { - LOGGER.info(rb.getString("loading.history.from.configuration")); + LOGGER.info(Utils.getLocalizedString("loading.history.from.configuration")); HISTORY.fromList(Utils.getConfigList("download.history")); if (HISTORY.toList().isEmpty()) { // Loaded from config, still no entries. // 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) { String url = RipUtils.urlFromDirectoryName(dir); if (url != null) { @@ -1160,13 +1224,15 @@ public final class MainWindow implements Runnable, RipStatusHandler { return; } String nextAlbum = (String) queueListModel.remove(0); - updateQueueLabel(); + + updateQueue(); + Thread t = ripAlbum(nextAlbum); if (t == null) { try { Thread.sleep(500); } 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(); } else { @@ -1175,7 +1241,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { } private Thread ripAlbum(String urlString) { - //shutdownCleanup(); + // shutdownCleanup(); if (!logPanel.isVisible()) { optionLog.doClick(); } @@ -1214,11 +1280,11 @@ public final class MainWindow implements Runnable, RipStatusHandler { status("Starting rip..."); ripper.setObserver(this); Thread t = new Thread(ripper); - if (configShowPopup.isSelected() && - (!mainFrame.isVisible() || !mainFrame.isActive())) { + if (configShowPopup.isSelected() && (!mainFrame.isVisible() || !mainFrame.isActive())) { mainFrame.toFront(); 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); } return t; @@ -1262,7 +1328,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { String rangeToParse = url.substring(url.indexOf("{") + 1, url.indexOf("}")); int rangeStart = Integer.parseInt(rangeToParse.split("-")[0]); 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)); if (canRip(realURL)) { queueListModel.add(queueListModel.size(), realURL); @@ -1307,9 +1373,9 @@ public final class MainWindow implements Runnable, RipStatusHandler { int completedPercent = evt.ripper.getCompletionPercentage(); statusProgress.setValue(completedPercent); statusProgress.setVisible(true); - status( evt.ripper.getStatusText() ); + status(evt.ripper.getStatusText()); - switch(msg.getStatus()) { + switch (msg.getStatus()) { case LOADING_RESOURCE: case DOWNLOAD_STARTED: if (LOGGER.isEnabledFor(Level.INFO)) { @@ -1365,7 +1431,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { entry.count = rsc.count; try { entry.title = ripper.getAlbumTitle(ripper.getURL()); - } catch (MalformedURLException e) { } + } catch (MalformedURLException e) { + } HISTORY.add(entry); historyTableModel.fireTableDataChanged(); } @@ -1384,10 +1451,10 @@ public final class MainWindow implements Runnable, RipStatusHandler { try { Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png")); openButton.setIcon(new ImageIcon(folderIcon)); - } catch (Exception e) { } - /* content key - * %path% the path to the album folder - * %url% is the album url + } catch (Exception e) { + } + /* + * content key %path% the path to the album folder %url% is the album url */ if (Utils.getConfigBoolean("enable.finish.command", false)) { try { @@ -1395,13 +1462,12 @@ public final class MainWindow implements Runnable, RipStatusHandler { commandToRun = commandToRun.replaceAll("%url%", url); commandToRun = commandToRun.replaceAll("%path%", f.getAbsolutePath()); 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); - BufferedReader stdInput = new BufferedReader(new - InputStreamReader(proc.getInputStream())); + BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); - BufferedReader stdError = new BufferedReader(new - InputStreamReader(proc.getErrorStream())); + BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream())); // read the output from the command LOGGER.info("Command output:\n"); @@ -1472,9 +1538,11 @@ public final class MainWindow implements Runnable, RipStatusHandler { private static boolean hasWindowPositionBug() { 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. - // 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"); } @@ -1500,8 +1568,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { return; } } - int x = (int)point.getX(); - int y = (int)point.getY(); + int x = (int) point.getX(); + int y = (int) point.getY(); int w = frame.getWidth(); int h = frame.getHeight(); Utils.setConfigInteger("window.x", x); diff --git a/src/main/java/com/rarchives/ripme/utils/Utils.java b/src/main/java/com/rarchives/ripme/utils/Utils.java index 8a8699a3..4333a9f5 100644 --- a/src/main/java/com/rarchives/ripme/utils/Utils.java +++ b/src/main/java/com/rarchives/ripme/utils/Utils.java @@ -50,6 +50,8 @@ public class Utils { private static HashMap> cookieCache; private static HashMap magicHash = new HashMap<>(); + private static ResourceBundle resourceBundle = null; + static { cookieCache = new HashMap<>(); @@ -83,6 +85,8 @@ public class Utils { } catch (Exception e) { LOGGER.error("[!] Failed to load properties file from " + CONFIG_FILE, e); } + + resourceBundle = getResourceBundle(null); } /** @@ -737,6 +741,19 @@ public class Utils { } } + public static void setLanguage(String langSelect) { + resourceBundle = getResourceBundle(langSelect); + } + + public static String getLanguage() { + return resourceBundle.getLocale().toString(); + } + + public static String getLocalizedString(String key) { + LOGGER.debug(String.format("Getting key %s in %s value %s",key, getLanguage(), resourceBundle.getString(key))); + return resourceBundle.getString(key); + } + /** * Formats and reuturns the status text for rippers using the byte progress bar * diff --git a/src/main/resources/LabelsBundle.properties b/src/main/resources/LabelsBundle.properties index 503d3b64..215e0f55 100644 --- a/src/main/resources/LabelsBundle.properties +++ b/src/main/resources/LabelsBundle.properties @@ -2,7 +2,7 @@ Log = Log History = History created = created modified = modified -Queue = Queue +queue = Queue Configuration = Configuration # Keys for the Configuration menu @@ -27,6 +27,11 @@ restore.window.position = Restore window position remember.url.history = Remember URL history loading.history.from = Loading history from +# 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 + # Misc UI keys loading.history.from.configuration = Loading history from configuration diff --git a/src/main/resources/LabelsBundle_ar_AR.properties b/src/main/resources/LabelsBundle_ar_AR.properties index 1a8443b0..3ec2ca73 100644 --- a/src/main/resources/LabelsBundle_ar_AR.properties +++ b/src/main/resources/LabelsBundle_ar_AR.properties @@ -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 created = \u0627\u0644\u0627\u0646\u0634\u0627\u0621 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 # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_de_DE.properties b/src/main/resources/LabelsBundle_de_DE.properties index 868ccec2..a7ec74f1 100644 --- a/src/main/resources/LabelsBundle_de_DE.properties +++ b/src/main/resources/LabelsBundle_de_DE.properties @@ -2,7 +2,7 @@ History = Verlauf created = erstellt modified = geändert -Queue = Queue +queue = Queue Configuration = Konfiguration # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_en_US.properties b/src/main/resources/LabelsBundle_en_US.properties index 503d3b64..7eb1fb85 100644 --- a/src/main/resources/LabelsBundle_en_US.properties +++ b/src/main/resources/LabelsBundle_en_US.properties @@ -1,57 +1 @@ -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 -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 \ No newline at end of file +# This need to be empty since EN is the default language in the bundles \ No newline at end of file diff --git a/src/main/resources/LabelsBundle_es_ES.properties b/src/main/resources/LabelsBundle_es_ES.properties index 88ba098f..c178ec79 100644 --- a/src/main/resources/LabelsBundle_es_ES.properties +++ b/src/main/resources/LabelsBundle_es_ES.properties @@ -2,7 +2,7 @@ Log = Log History = Historia created = creado modified = modificado -Queue = Cola +queue = Cola Configuration = Configuracion # Keys for the Configuration menu @@ -27,6 +27,11 @@ restore.window.position = Restaurar posicion de ventana remember.url.history = Recordar historia URL 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 loading.history.from.configuration = Cargando historia desde la configuracion diff --git a/src/main/resources/LabelsBundle_fi_FI.properties b/src/main/resources/LabelsBundle_fi_FI.properties index 4cc4fbe0..6edd4e45 100644 --- a/src/main/resources/LabelsBundle_fi_FI.properties +++ b/src/main/resources/LabelsBundle_fi_FI.properties @@ -2,7 +2,7 @@ Log = Logi History = Historia created = luotu modified = muokattu -Queue = Jono +queue = Jono Configuration = Asetukset # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_fr_CH.properties b/src/main/resources/LabelsBundle_fr_CH.properties index 6b2d7c1c..b489e3e3 100644 --- a/src/main/resources/LabelsBundle_fr_CH.properties +++ b/src/main/resources/LabelsBundle_fr_CH.properties @@ -2,7 +2,7 @@ Log = Journal History = Historique created = créé le modified = modifié le -Queue = File d'attente +queue = File d'attente Configuration = Configuration # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_in_ID.properties b/src/main/resources/LabelsBundle_in_ID.properties index 6792df56..b5e773d5 100644 --- a/src/main/resources/LabelsBundle_in_ID.properties +++ b/src/main/resources/LabelsBundle_in_ID.properties @@ -2,7 +2,7 @@ Log = Log History = Riwayat created = dibuat pada modified = diubah pada -Queue = Antrian +queue = Antrian Configuration = Pengaturan # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_it_IT.properties b/src/main/resources/LabelsBundle_it_IT.properties index f3fdb132..de00612b 100644 --- a/src/main/resources/LabelsBundle_it_IT.properties +++ b/src/main/resources/LabelsBundle_it_IT.properties @@ -2,7 +2,7 @@ Log = Log History = Cronologia created = creato modified = modificato -Queue = Coda +queue = Coda Configuration = Configurazione # Keys for the Configuration menu @@ -44,14 +44,14 @@ nonretriable.status.code = Codice di stato irreversibile retriable.status.code = Codice di stato reversibile server.doesnt.support.resuming.downloads = Il server non supporta la ripresa dei download # A "magic number" can also be called a file signature -was.unable.to.get.content.type.using.magic.number = Non stato possibile ottenere il tipo del contenuto usando magic number +was.unable.to.get.content.type.using.magic.number = Non � stato possibile ottenere il tipo del contenuto usando magic number magic.number.was = Magic number era deleting.existing.file = Cancellazione file esistente -request.properties = Richiesta propriet +request.properties = Richiesta propriet� download.interrupted = Download interrotto exceeded.maximum.retries = Superato il numero massimo di tentativi http.status.exception = Eccezione stato HTTP exception.while.downloading.file = Eccezione durante il download del file failed.to.download = Download non riuscito skipping = Saltare -file.already.exists = il file esiste gi \ No newline at end of file +file.already.exists = il file esiste gi� \ No newline at end of file diff --git a/src/main/resources/LabelsBundle_kr_KR.properties b/src/main/resources/LabelsBundle_kr_KR.properties index 5fefcecc..34a35a7a 100644 --- a/src/main/resources/LabelsBundle_kr_KR.properties +++ b/src/main/resources/LabelsBundle_kr_KR.properties @@ -2,7 +2,7 @@ Log = \uB85C\uADF8 History = \uD788\uC2A4\uD1A0\uB9AC created = \uC0DD\uC0B0\uB428 modified = \uC218\uC815\uB428 -Queue = \uB300\uAE30\uC5F4 +queue = \uB300\uAE30\uC5F4 Configuration = \uAD6C\uC131 # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_nl_NL.properties b/src/main/resources/LabelsBundle_nl_NL.properties index ce3308f6..e1d9d61c 100644 --- a/src/main/resources/LabelsBundle_nl_NL.properties +++ b/src/main/resources/LabelsBundle_nl_NL.properties @@ -2,7 +2,7 @@ Log = Logboek History = Geschiedenis created = gemaakt modified = aangepast -Queue = Wachtrij +queue = Wachtrij Configuration = Configuratie # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_pl_PL.properties b/src/main/resources/LabelsBundle_pl_PL.properties index 719cfac8..2a6ba326 100644 --- a/src/main/resources/LabelsBundle_pl_PL.properties +++ b/src/main/resources/LabelsBundle_pl_PL.properties @@ -2,7 +2,7 @@ History = Historia created = Stworzono modified = Zmodyfikowano -Queue = Kolejka +queue = Kolejka Configuration = Konfiguracja # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_porrisavvo_FI.properties b/src/main/resources/LabelsBundle_porrisavvo_FI.properties index 93c02c38..a2ba056e 100644 --- a/src/main/resources/LabelsBundle_porrisavvo_FI.properties +++ b/src/main/resources/LabelsBundle_porrisavvo_FI.properties @@ -2,7 +2,7 @@ Log = Loki History = Historriijja created = luatu modified = muakat -Queue = Jono +queue = Jono Configuration = Assetuksse # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_pt_BR.properties b/src/main/resources/LabelsBundle_pt_BR.properties index 3122c5e0..88209235 100644 --- a/src/main/resources/LabelsBundle_pt_BR.properties +++ b/src/main/resources/LabelsBundle_pt_BR.properties @@ -2,7 +2,7 @@ Log = Registro History = Histórico created = criado modified = modificado -Queue = Fila +queue = Fila Configuration = Configuração # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_pt_PT.properties b/src/main/resources/LabelsBundle_pt_PT.properties index 7f2cc55b..0925dfb5 100644 --- a/src/main/resources/LabelsBundle_pt_PT.properties +++ b/src/main/resources/LabelsBundle_pt_PT.properties @@ -2,7 +2,7 @@ Log = Registo History = Histórico created = criado modified = modificado -Queue = Fila +queue = Fila Configuration = Configuração # Keys for the Configuration menu diff --git a/src/main/resources/LabelsBundle_ru_RU.properties b/src/main/resources/LabelsBundle_ru_RU.properties index 0a69f8da..9a97dfa6 100644 --- a/src/main/resources/LabelsBundle_ru_RU.properties +++ b/src/main/resources/LabelsBundle_ru_RU.properties @@ -2,7 +2,7 @@ History = История created = создано modified = изменено -Queue = Очередь +queue = Очередь Configuration = Настройки # Keys for the Configuration menu From a3bbf8198b3f543ecd79c40ff00be2b988d295ee Mon Sep 17 00:00:00 2001 From: Isaaku Date: Wed, 14 Aug 2019 17:16:21 -0500 Subject: [PATCH 12/16] Added missing history properties to LabelsBundle --- .../ripme/ui/HistoryMenuMouseListener.java | 10 +++--- .../com/rarchives/ripme/ui/MainWindow.java | 32 ++++++++----------- src/main/resources/LabelsBundle.properties | 27 ++++++++++++---- workspace.code-workspace | 16 ++++++++++ 4 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 workspace.code-workspace diff --git a/src/main/java/com/rarchives/ripme/ui/HistoryMenuMouseListener.java b/src/main/java/com/rarchives/ripme/ui/HistoryMenuMouseListener.java index 61037626..9044531f 100644 --- a/src/main/java/com/rarchives/ripme/ui/HistoryMenuMouseListener.java +++ b/src/main/java/com/rarchives/ripme/ui/HistoryMenuMouseListener.java @@ -10,13 +10,15 @@ import javax.swing.Action; import javax.swing.JPopupMenu; import javax.swing.JTable; +import com.rarchives.ripme.utils.Utils; + class HistoryMenuMouseListener extends MouseAdapter { private JPopupMenu popup = new JPopupMenu(); private JTable tableComponent; @SuppressWarnings("serial") public HistoryMenuMouseListener() { - Action checkAllAction = new AbstractAction("Check All") { + Action checkAllAction = new AbstractAction(Utils.getLocalizedString("history.check.all")) { @Override public void actionPerformed(ActionEvent ae) { for (int row = 0; row < tableComponent.getRowCount(); row++) { @@ -26,7 +28,7 @@ class HistoryMenuMouseListener extends MouseAdapter { }; popup.add(checkAllAction); - Action uncheckAllAction = new AbstractAction("Check None") { + Action uncheckAllAction = new AbstractAction(Utils.getLocalizedString("history.check.none")) { @Override public void actionPerformed(ActionEvent ae) { for (int row = 0; row < tableComponent.getRowCount(); row++) { @@ -38,7 +40,7 @@ class HistoryMenuMouseListener extends MouseAdapter { popup.addSeparator(); - Action checkSelected = new AbstractAction("Check Selected") { + Action checkSelected = new AbstractAction(Utils.getLocalizedString("history.check.selected")) { @Override public void actionPerformed(ActionEvent ae) { for (int row : tableComponent.getSelectedRows()) { @@ -48,7 +50,7 @@ class HistoryMenuMouseListener extends MouseAdapter { }; popup.add(checkSelected); - Action uncheckSelected = new AbstractAction("Uncheck Selected") { + Action uncheckSelected = new AbstractAction(Utils.getLocalizedString("history.uncheck.selected")) { @Override public void actionPerformed(ActionEvent ae) { for (int row : tableComponent.getSelectedRows()) { diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java index 2d69542c..bbc656be 100644 --- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java +++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java @@ -849,8 +849,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { // Re-rip all history historyButtonRerip.addActionListener(event -> { if (HISTORY.isEmpty()) { - JOptionPane.showMessageDialog(null, "There are no history entries to re-rip. Rip some albums first", - "RipMe Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, Utils.getLocalizedString("history.load.none"), "RipMe Error", + JOptionPane.ERROR_MESSAGE); return; } int added = 0; @@ -861,8 +861,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { } } if (added == 0) { - JOptionPane.showMessageDialog(null, "No history entries have been 'Checked'\n" - + "Check an entry by clicking the checkbox to the right of the URL or Right-click a URL to check/uncheck all items", + JOptionPane.showMessageDialog(null, Utils.getLocalizedString("history.load.none.checked"), "RipMe Error", JOptionPane.ERROR_MESSAGE); } }); @@ -1009,26 +1008,26 @@ public final class MainWindow implements Runnable, RipStatusHandler { mainFrame.addWindowListener(new WindowAdapter() { @Override public void windowActivated(WindowEvent e) { - trayMenuMain.setLabel("Hide"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide")); } @Override public void windowDeactivated(WindowEvent e) { - trayMenuMain.setLabel("Show"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.show")); } @Override public void windowDeiconified(WindowEvent e) { - trayMenuMain.setLabel("Hide"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide")); } @Override public void windowIconified(WindowEvent e) { - trayMenuMain.setLabel("Show"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.show")); } }); PopupMenu trayMenu = new PopupMenu(); - trayMenuMain = new MenuItem("Hide"); + trayMenuMain = new MenuItem(Utils.getLocalizedString("tray.hide")); trayMenuMain.addActionListener(arg0 -> toggleTrayClick()); MenuItem trayMenuAbout = new MenuItem("About " + mainFrame.getTitle()); trayMenuAbout.addActionListener(arg0 -> { @@ -1079,9 +1078,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)); - trayMenuAutorip = new CheckboxMenuItem("Clipboard Autorip"); + trayMenuAutorip = new CheckboxMenuItem(Utils.getLocalizedString("tray.autorip")); trayMenuAutorip.addItemListener(arg0 -> { ClipboardUtils.setClipboardAutoRip(trayMenuAutorip.getState()); configClipboardAutorip.setSelected(trayMenuAutorip.getState()); @@ -1122,10 +1121,10 @@ public final class MainWindow implements Runnable, RipStatusHandler { mainFrame.setVisible(true); mainFrame.setAlwaysOnTop(true); mainFrame.setAlwaysOnTop(false); - trayMenuMain.setLabel("Hide"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.hide")); } else { mainFrame.setVisible(false); - trayMenuMain.setLabel("Show"); + trayMenuMain.setLabel(Utils.getLocalizedString("tray.show")); } } @@ -1170,10 +1169,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { } catch (IOException e) { LOGGER.error("Failed to load history from file " + historyFile, e); JOptionPane.showMessageDialog(null, - "RipMe failed to load the history file at " + historyFile.getAbsolutePath() + "\n\n" + "Error: " - + e.getMessage() + "\n\n" - + "Closing RipMe will automatically overwrite the contents of this file,\n" - + "so you may want to back the file up before closing RipMe!", + String.format(Utils.getLocalizedString("history.load.failed.warning"), e.getMessage()), "RipMe - history load failure", JOptionPane.ERROR_MESSAGE); } } else { @@ -1446,7 +1442,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { openButton.setVisible(true); File f = rsc.dir; String prettyFile = Utils.shortenPath(f); - openButton.setText("Open " + prettyFile); + openButton.setText(Utils.getLocalizedString("open") + prettyFile); mainFrame.setTitle("RipMe v" + UpdateUtils.getThisJarVersion()); try { Image folderIcon = ImageIO.read(getClass().getClassLoader().getResource("folder.png")); diff --git a/src/main/resources/LabelsBundle.properties b/src/main/resources/LabelsBundle.properties index 215e0f55..575f4f8e 100644 --- a/src/main/resources/LabelsBundle.properties +++ b/src/main/resources/LabelsBundle.properties @@ -4,9 +4,9 @@ created = created modified = modified queue = Queue Configuration = Configuration +open = Open # Keys for the Configuration menu - current.version = Current version check.for.updates = Check for updates auto.update = Auto-update? @@ -32,19 +32,32 @@ queue.remove.all = Remove All queue.validation = Are you sure you want to remove all elements from the queue? queue.remove.selected = Remove Selected -# 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 +# History re-rip.checked = Re-rip Checked remove = Remove 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 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 diff --git a/workspace.code-workspace b/workspace.code-workspace new file mode 100644 index 00000000..95b80106 --- /dev/null +++ b/workspace.code-workspace @@ -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" + } +} \ No newline at end of file From 03e8c2d797a6b6764d0bd9575d8836aef29c8ea2 Mon Sep 17 00:00:00 2001 From: Isaaku Date: Thu, 15 Aug 2019 12:52:28 -0500 Subject: [PATCH 13/16] Get supported languages dynamically --- .../com/rarchives/ripme/ui/MainWindow.java | 12 +-- .../java/com/rarchives/ripme/utils/Utils.java | 34 ++++++- .../ripme/tst/ui/LabelsBundlesTest.java | 95 +++++++++++++++++++ 3 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java diff --git a/src/main/java/com/rarchives/ripme/ui/MainWindow.java b/src/main/java/com/rarchives/ripme/ui/MainWindow.java index bbc656be..7151f6b1 100644 --- a/src/main/java/com/rarchives/ripme/ui/MainWindow.java +++ b/src/main/java/com/rarchives/ripme/ui/MainWindow.java @@ -139,10 +139,6 @@ public final class MainWindow implements Runnable, RipStatusHandler { private static AbstractRipper ripper; - // All the langs ripme has been translated into - 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 updateQueue(DefaultListModel model) { if (model == null) model = queueListModel; @@ -483,7 +479,7 @@ public final class MainWindow implements Runnable, RipStatusHandler { queueListModel = new DefaultListModel(); JList queueList = new JList(queueListModel); queueList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - queueList.addMouseListener(queueMenuMouseListener = new QueueMenuMouseListener((model) -> updateQueue(model))); + queueList.addMouseListener(queueMenuMouseListener = new QueueMenuMouseListener()); JScrollPane queueListScroll = new JScrollPane(queueList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); for (String item : Utils.getConfigList("queue")) { @@ -539,8 +535,8 @@ public final class MainWindow implements Runnable, RipStatusHandler { configLogLevelCombobox = new JComboBox<>( new String[] { "Log level: Error", "Log level: Warn", "Log level: Info", "Log level: Debug" }); - configSelectLangComboBox = new JComboBox<>(supportedLanges); - configSelectLangComboBox.setSelectedItem(Utils.getLanguage()); + configSelectLangComboBox = new JComboBox<>(Utils.getSupportedLanguages()); + configSelectLangComboBox.setSelectedItem(Utils.getSelectedLanguage()); configLogLevelCombobox.setSelectedItem(Utils.getConfigString("log.level", "Log level: Debug")); setLogLevel(configLogLevelCombobox.getSelectedItem().toString()); configSaveDirLabel = new JLabel(); @@ -675,8 +671,6 @@ public final class MainWindow implements Runnable, RipStatusHandler { optionHistory.setText(Utils.getLocalizedString("History")); optionQueue.setText(Utils.getLocalizedString("queue")); optionConfiguration.setText(Utils.getLocalizedString("Configuration")); - - queueMenuMouseListener.updateUI(); } private void setupHandlers() { diff --git a/src/main/java/com/rarchives/ripme/utils/Utils.java b/src/main/java/com/rarchives/ripme/utils/Utils.java index 4333a9f5..e038fea0 100644 --- a/src/main/java/com/rarchives/ripme/utils/Utils.java +++ b/src/main/java/com/rarchives/ripme/utils/Utils.java @@ -2,6 +2,7 @@ package com.rarchives.ripme.utils; import java.io.File; import java.io.FileNotFoundException; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -21,6 +22,8 @@ import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; @@ -40,6 +43,7 @@ import org.apache.log4j.PropertyConfigurator; */ public class Utils { + private static final Pattern pattern = Pattern.compile("LabelsBundle_(?[A-Za-z_]+).properties"); private static final String RIP_DIRECTORY = "rips"; private static final String CONFIG_FILE = "rip.properties"; private static final String OS = System.getProperty("os.name").toLowerCase(); @@ -745,12 +749,38 @@ public class Utils { resourceBundle = getResourceBundle(langSelect); } - public static String getLanguage() { + public static String getSelectedLanguage() { return resourceBundle.getLocale().toString(); } + // All the langs ripme has been translated into + public static String[] getSupportedLanguages() { + File configFile = new File(Utils.class.getResource("/rip.properties").getFile()); + LOGGER.info("ConfigFile: " + configFile); + LOGGER.info("Parent: " + new File(configFile.getParent())); + File[] files = new File(configFile.getParent()).listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + LOGGER.info("name: " + name); + return name.startsWith("LabelsBundle_"); + } + + }); + + String[] langs = new String[files.length]; + for (int i = 0; i < files.length; i++) { + Matcher matcher = pattern.matcher(files[i].getName()); + if (matcher.find()) + langs[i] = matcher.group("lang"); + } + + return langs; + } + public static String getLocalizedString(String key) { - LOGGER.debug(String.format("Getting key %s in %s value %s",key, getLanguage(), resourceBundle.getString(key))); + LOGGER.debug(String.format("Getting key %s in %s value %s", key, getSelectedLanguage(), + resourceBundle.getString(key))); return resourceBundle.getString(key); } diff --git a/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java b/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java new file mode 100644 index 00000000..58fd5d34 --- /dev/null +++ b/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java @@ -0,0 +1,95 @@ +package com.rarchives.ripme.tst.ui; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.rarchives.ripme.utils.Utils; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.jupiter.api.Test; + +public class LabelsBundlesTest { + + private Logger logger = Logger.getLogger(Utils.class); + + @Test + void testKeyCount() { + ((ConsoleAppender) Logger.getRootLogger().getAppender("stdout")).setThreshold(Level.DEBUG); + File f = new File("E:\\Downloads\\_Isaaku\\dev\\ripme-1.7.86-jar-with-dependencies.jar"); + File[] files = f.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + logger.info("name: " + name); + return name.startsWith("LabelsBundle_"); + } + + }); + + for (String s : getResourcesNames("\\**")) { + logger.info(s); + } + + } + + public String[] getResourcesNames(String path) { + Class loader = getClassLoader(); + /*URL u = loader.getResource("/rip.properties"); + path = u.getFile(); + path = new File(path).getParent();*/ + + try { + URL url = loader.getResource(path); + if (url == null) { + return null; + } + + URI uri = url.toURI(); + if (uri.getScheme().equals("jar")) { // Run from jar + try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap())) { + Path resourcePath = fileSystem.getPath(path); + + // Get all contents of a resource (skip resource itself), if entry is a + // directory remove trailing / + List resourcesNames = Files.walk(resourcePath, 1).skip(1).map(p -> { + String name = p.getFileName().toString(); + if (name.endsWith("/")) { + name = name.substring(0, name.length() - 1); + } + return name; + }).sorted().collect(Collectors.toList()); + + return resourcesNames.toArray(new String[resourcesNames.size()]); + } + } else { // Run from IDE + File resource = new File(uri); + return resource.list(); + } + } catch (IOException e) { + return null; + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + return null; + } + } + + private Class getClassLoader() { + return Utils.class; + //return Thread.currentThread().getContextClassLoader(); + } +} \ No newline at end of file From 5545677cfefae6481470c51eeb9c867b74a845ac Mon Sep 17 00:00:00 2001 From: Isaaku Date: Fri, 23 Aug 2019 16:28:02 -0500 Subject: [PATCH 14/16] Fix get supported languages dynamically Remove UTF8-BOM from de_DE, pl_PL and ru_RU bundles Added test to find is there is a Key in a language bundle but not in the default bundle Added test to list keys missing from a language bundle --- .../java/com/rarchives/ripme/utils/Utils.java | 49 +++++--- .../resources/LabelsBundle_de_DE.properties | 2 +- .../resources/LabelsBundle_pl_PL.properties | 2 +- .../resources/LabelsBundle_ru_RU.properties | 2 +- .../ripme/tst/ui/LabelsBundlesTest.java | 116 +++++++----------- 5 files changed, 77 insertions(+), 94 deletions(-) diff --git a/src/main/java/com/rarchives/ripme/utils/Utils.java b/src/main/java/com/rarchives/ripme/utils/Utils.java index e038fea0..98ed8895 100644 --- a/src/main/java/com/rarchives/ripme/utils/Utils.java +++ b/src/main/java/com/rarchives/ripme/utils/Utils.java @@ -7,14 +7,22 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; 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.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -24,6 +32,7 @@ import java.util.jar.JarEntry; 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.Clip; @@ -44,6 +53,7 @@ import org.apache.log4j.PropertyConfigurator; public class Utils { private static final Pattern pattern = Pattern.compile("LabelsBundle_(?[A-Za-z_]+).properties"); + private static final String DEFAULT_LANG = "en_US"; private static final String RIP_DIRECTORY = "rips"; private static final String CONFIG_FILE = "rip.properties"; private static final String OS = System.getProperty("os.name").toLowerCase(); @@ -755,27 +765,34 @@ public class Utils { // All the langs ripme has been translated into public static String[] getSupportedLanguages() { - File configFile = new File(Utils.class.getResource("/rip.properties").getFile()); - LOGGER.info("ConfigFile: " + configFile); - LOGGER.info("Parent: " + new File(configFile.getParent())); - File[] files = new File(configFile.getParent()).listFiles(new FilenameFilter() { + ArrayList filesList = new ArrayList<>(); + try { + URI uri = Utils.class.getResource("/rip.properties").toURI(); - @Override - public boolean accept(File dir, String name) { - LOGGER.info("name: " + name); - return name.startsWith("LabelsBundle_"); + Path myPath; + if (uri.getScheme().equals("jar")) { + FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.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[files.length]; - for (int i = 0; i < files.length; i++) { - Matcher matcher = pattern.matcher(files[i].getName()); - if (matcher.find()) - langs[i] = matcher.group("lang"); + 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 }; } - - return langs; } public static String getLocalizedString(String key) { diff --git a/src/main/resources/LabelsBundle_de_DE.properties b/src/main/resources/LabelsBundle_de_DE.properties index a7ec74f1..61461aba 100644 --- a/src/main/resources/LabelsBundle_de_DE.properties +++ b/src/main/resources/LabelsBundle_de_DE.properties @@ -1,4 +1,4 @@ -Log = Log +Log = Log History = Verlauf created = erstellt modified = geändert diff --git a/src/main/resources/LabelsBundle_pl_PL.properties b/src/main/resources/LabelsBundle_pl_PL.properties index 2a6ba326..4ba4590e 100644 --- a/src/main/resources/LabelsBundle_pl_PL.properties +++ b/src/main/resources/LabelsBundle_pl_PL.properties @@ -1,4 +1,4 @@ -Log = Logi +Log = Logi History = Historia created = Stworzono modified = Zmodyfikowano diff --git a/src/main/resources/LabelsBundle_ru_RU.properties b/src/main/resources/LabelsBundle_ru_RU.properties index 9a97dfa6..a3100df8 100644 --- a/src/main/resources/LabelsBundle_ru_RU.properties +++ b/src/main/resources/LabelsBundle_ru_RU.properties @@ -1,4 +1,4 @@ -Log = Лог +Log = Лог History = История created = создано modified = изменено diff --git a/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java b/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java index 58fd5d34..6189d86a 100644 --- a/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java +++ b/src/test/java/com/rarchives/ripme/tst/ui/LabelsBundlesTest.java @@ -1,95 +1,61 @@ package com.rarchives.ripme.tst.ui; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; +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.ConsoleAppender; -import org.apache.log4j.Level; 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() { - ((ConsoleAppender) Logger.getRootLogger().getAppender("stdout")).setThreshold(Level.DEBUG); - File f = new File("E:\\Downloads\\_Isaaku\\dev\\ripme-1.7.86-jar-with-dependencies.jar"); - File[] files = f.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File dir, String name) { - logger.info("name: " + name); - return name.startsWith("LabelsBundle_"); - } - - }); - - for (String s : getResourcesNames("\\**")) { - logger.info(s); - } - - } - - public String[] getResourcesNames(String path) { - Class loader = getClassLoader(); - /*URL u = loader.getResource("/rip.properties"); - path = u.getFile(); - path = new File(path).getParent();*/ - - try { - URL url = loader.getResource(path); - if (url == null) { - return null; - } - - URI uri = url.toURI(); - if (uri.getScheme().equals("jar")) { // Run from jar - try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap())) { - Path resourcePath = fileSystem.getPath(path); - - // Get all contents of a resource (skip resource itself), if entry is a - // directory remove trailing / - List resourcesNames = Files.walk(resourcePath, 1).skip(1).map(p -> { - String name = p.getFileName().toString(); - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - return name; - }).sorted().collect(Collectors.toList()); - - return resourcesNames.toArray(new String[resourcesNames.size()]); + ResourceBundle defaultBundle = Utils.getResourceBundle(null); + HashMap> dictionary = new HashMap<>(); + for (String lang : Utils.getSupportedLanguages()) { + ResourceBundle.clearCache(); + if (lang.equals(DEFAULT_LANG)) + continue; + ResourceBundle selectedLang = Utils.getResourceBundle(lang); + for (final Enumeration 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); } - } else { // Run from IDE - File resource = new File(uri); - return resource.list(); } - } catch (IOException e) { - return null; - } catch (URISyntaxException e) { - // TODO Auto-generated catch block - return null; } + + dictionary.keySet().forEach(d -> { + logger.warn(String.format("Keys missing in %s", d)); + dictionary.get(d).forEach(v -> logger.warn(v)); + logger.warn("\n"); + }); } - private Class getClassLoader() { - return Utils.class; - //return Thread.currentThread().getContextClassLoader(); + @Test + void testKeyName() { + ResourceBundle defaultBundle = Utils.getResourceBundle(null); + Set 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)); + } + } } } \ No newline at end of file From 7c1858d9de5c97e676fae3082192ed099840b752 Mon Sep 17 00:00:00 2001 From: Isaac Urdaneta Date: Thu, 29 Aug 2019 16:44:47 -0500 Subject: [PATCH 15/16] Added GitHub Actions Tests --- .github/workflows/maven.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000..243272ec --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,21 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + java: [1.8, 1.9] + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: Build with Maven + run: mvn package --file pom.xml From 0bed1364670b118828eaa9d1a3e703d1826f5e9a Mon Sep 17 00:00:00 2001 From: Isaac Urdaneta Date: Fri, 30 Aug 2019 13:24:04 -0500 Subject: [PATCH 16/16] Added on pull request event --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 243272ec..93719005 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,6 +1,6 @@ name: Java CI -on: [push] +on: [push, pull_request] jobs: build: