diff --git a/nbactions.xml b/nbactions.xml
index cc17048..bc1bcdc 100644
--- a/nbactions.xml
+++ b/nbactions.xml
@@ -1,17 +1,46 @@
-
-
-
- run
-
- jar
-
-
- process-classes
- org.codehaus.mojo:exec-maven-plugin:1.5.0:exec
-
-
- -classpath %classpath com.greinet.tvtotalripper.Main
- java
-
-
-
+
+
+
+ run
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:1.5.0:exec
+
+
+ -classpath %classpath com.greinet.tvtotalripper.ui.RipperWindow
+ java
+
+
+
+ debug
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:1.5.0:exec
+
+
+ -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.greinet.tvtotalripper.ui.RipperWindow
+ java
+ true
+
+
+
+ profile
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:1.5.0:exec
+
+
+ -classpath %classpath com.greinet.tvtotalripper.ui.RipperWindow
+ java
+
+
+
diff --git a/src/main/java/com/greinet/tvtotalripper/Main.java b/src/main/java/com/greinet/tvtotalripper/Main.java
deleted file mode 100644
index 5ddcb0e..0000000
--- a/src/main/java/com/greinet/tvtotalripper/Main.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.greinet.tvtotalripper;
-
-import com.greinet.tvtotalripper.crawler.CrawlerUtil;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.stream.Collectors;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.mp4parser.IsoFile;
-import org.mp4parser.boxes.apple.AppleNameBox;
-import org.mp4parser.tools.Path;
-import org.openqa.selenium.By;
-import org.openqa.selenium.TimeoutException;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.chrome.ChromeDriver;
-import org.openqa.selenium.chrome.ChromeOptions;
-import org.openqa.selenium.support.ui.ExpectedConditions;
-import org.openqa.selenium.support.ui.WebDriverWait;
-
-/**
- *
- * @author agreiner
- */
-public class Main {
-
- private static final Logger logger = LogManager.getLogger(Main.class);
-
-
- public static void main(String[] args) throws InterruptedException, IOException {
- //System.setProperty("webdriver.chrome.driver", "resources/chromedriver.exe");
- File f = new File("H:/Users/Andreas/Music/Bass/videoplayback.mp4");
-
- MetaDataWriter mdp = new MetaDataWriter();
- mdp.writeMetadata(f.getAbsolutePath(), "Raab im Dschungel", "Stefan Raab", "TV Total", "TV Total vom 3.2.2021");
-
-
- System.exit(0);
-
-
-
- System.out.println(CrawlerUtil.getFetchfileURL("https://www.myspass.de/shows/tvshows/tv-total/TV-total-Sendung-vom-08031999--/5716/"));
-
-
-
-
-
- downloadFile(test());
-
-
-
-
- ChromeOptions options = new ChromeOptions();
- options.addArguments("start-maximized");
-
- WebDriver driver = new ChromeDriver(options);
-
- initialize(driver);
-
- List seriesElements = getSeriesElements(driver);
- //seriesElements.forEach(e -> System.out.println(e.getAttribute("href").replaceAll("https://www.myspass.de/shows/tvshows/", "")));
-
- System.out.println("\nTV shows\n");
- // TV shows
- List tvshows = seriesElements.stream().filter(e -> e.getAttribute("href").contains("tvshows") || e.getAttribute("href").contains("UNKNOWN")).collect(Collectors.toList());
- tvshows.forEach(e -> System.out.println(e.getAttribute("href")));
-
- System.out.println("\nWebshows\n");
- List webshows = seriesElements.stream().filter(e -> e.getAttribute("href").contains("webshows")).collect(Collectors.toList());
- webshows.forEach(e -> System.out.println(e.getAttribute("href")));
-
-
- tvshows.get(3).click();
- Thread.sleep(3000);
- navigateToEpisodeOverview(driver);
- Thread.sleep(3000);
- getSeasonElements(driver).forEach(e -> System.out.println(e.getText()));
- Thread.sleep(3000);
- System.out.println("-------------------------------------------------------------------------------------------------------------------------------------");
- getEpisodeElements(driver).forEach(e -> System.out.println(e.getAttribute("href")));
- }
-
- private static boolean clickWhenClickable(WebDriver driver, By by, int timeout){
- WebDriverWait wait = new WebDriverWait(driver, timeout);
- try{
- WebElement acceptCookiesButton = wait.until(ExpectedConditions.elementToBeClickable(by));
- acceptCookiesButton.click();
- }catch(TimeoutException ex){
- logger.warn("Element represented by ["+by+"] not clickable.");
- return false;
- }
- return true;
- }
-
- private static void initialize(WebDriver driver){
- //Load start page
- //String urlStartPage = "https://www.myspass.de/shows/tvshows/tv-total/#bob-subnavi";
- String urlStartPage = "https://www.myspass.de/sendungen-a-bis-z/";
- logger.info("Loading start page ["+urlStartPage+"].");
- driver.get(urlStartPage);
-
- // Accept cookies if needed
- logger.info("Accepting cookies.");
- boolean cookiesSuccess = clickWhenClickable(driver, By.id("cmpbntyestxt"),5);
- if(!cookiesSuccess){
- logger.info("No cookie popup present.");
- }
- }
-
- private static boolean navigateToEpisodeOverview(WebDriver driver){
- logger.info("Navigating to episode overview.");
- return clickWhenClickable(driver, By.xpath("/html/body/div[4]/div[1]/div[2]/ul/li[2]/a"),5);
- }
-
- private static List getSeriesElements(WebDriver driver){
- return driver.findElements(By.xpath("/html/body/div[5]/div/div/div/div/a"));
- }
-
- private static List getSeasonElements(WebDriver driver){
- return driver.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[1]/select/option"));
- }
-
- private static List getEpisodeElements(WebDriver driver){
- return driver.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[4]/div/div/div/a"));
- }
-
- private static String test(){
- WebDriver driver = new ChromeDriver();
- driver.get("https://de.fetchfile.net/herunterladen-von-myspass/");
-
- WebElement textbox = driver.findElement(By.id("videoPath"));
- textbox.sendKeys("https://www.myspass.de/shows/tvshows/tv-total/TV-total-Sendung-vom-05012015--/20674/");
-
- WebElement dlButton = driver.findElement(By.id("home-submit"));
- dlButton.click();
-
- WebDriverWait wait = new WebDriverWait(driver, 20);
- WebElement vidButton = wait.until(ExpectedConditions.elementToBeClickable(By.className("download-link")));
- return vidButton.getAttribute("href");
-
- }
-
-
- private static void downloadFile(String urlString){
- try {
- File f = new File("download.mp4");
- f.createNewFile();
- URL url = new URL(urlString);
- ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
- FileOutputStream fileOutputStream = new FileOutputStream(f);
- fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
- } catch (MalformedURLException ex) {
-
- } catch (IOException ex) {
- java.util.logging.Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
- }
-
- }
-}
diff --git a/src/main/java/com/greinet/tvtotalripper/MetaDataParser.java b/src/main/java/com/greinet/tvtotalripper/MetaDataParser.java
deleted file mode 100644
index 3cb2ff2..0000000
--- a/src/main/java/com/greinet/tvtotalripper/MetaDataParser.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package com.greinet.tvtotalripper;
-
-
-import org.mp4parser.Box;
-import org.mp4parser.Container;
-import org.mp4parser.IsoFile;
-import org.mp4parser.boxes.apple.AppleItemListBox;
-import org.mp4parser.boxes.apple.AppleNameBox;
-import org.mp4parser.boxes.iso14496.part12.*;
-import org.mp4parser.tools.Path;
-
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.util.List;
-
-/**
- * Change metadata and make sure chunkoffsets are corrected.
- */
-public class MetaDataParser {
-
- public FileChannel splitFileAndInsert(File f, long pos, long length) throws IOException {
- FileChannel read = new RandomAccessFile(f, "r").getChannel();
- File tmp = File.createTempFile("ChangeMetaData", "splitFileAndInsert");
- FileChannel tmpWrite = new RandomAccessFile(tmp, "rw").getChannel();
- read.position(pos);
- tmpWrite.transferFrom(read, 0, read.size() - pos);
- read.close();
- FileChannel write = new RandomAccessFile(f, "rw").getChannel();
- write.position(pos + length);
- tmpWrite.position(0);
- long transferred = 0;
- while ((transferred += tmpWrite.transferTo(0, tmpWrite.size() - transferred, write)) != tmpWrite.size()) {
- System.out.println(transferred);
- }
- System.out.println(transferred);
- tmpWrite.close();
- tmp.delete();
- return write;
- }
-
-
- private boolean needsOffsetCorrection(IsoFile isoFile) {
- if (Path.getPath(isoFile, "moov[0]/mvex[0]") != null) {
- // Fragmented files don't need a correction
- return false;
- } else {
- // no correction needed if mdat is before moov as insert into moov want change the offsets of mdat
- for (Box box : isoFile.getBoxes()) {
- if ("moov".equals(box.getType())) {
- return true;
- }
- if ("mdat".equals(box.getType())) {
- return false;
- }
- }
- throw new RuntimeException("I need moov or mdat. Otherwise all this doesn't make sense");
- }
- }
-
- public void writeRandomMetadata(String videoFilePath, String title) throws IOException {
-
- File videoFile = new File(videoFilePath);
- if (!videoFile.exists()) {
- throw new FileNotFoundException("File " + videoFilePath + " not exists");
- }
-
- if (!videoFile.canWrite()) {
- throw new IllegalStateException("No write permissions to file " + videoFilePath);
- }
- IsoFile isoFile = new IsoFile(videoFilePath);
-
- MovieBox moov = isoFile.getBoxes(MovieBox.class).get(0);
- FreeBox freeBox = findFreeBox(moov);
-
- boolean correctOffset = needsOffsetCorrection(isoFile);
- long sizeBefore = moov.getSize();
- long offset = 0;
- for (Box box : isoFile.getBoxes()) {
- if ("moov".equals(box.getType())) {
- break;
- }
- offset += box.getSize();
- }
-
- // Create structure or just navigate to Apple List Box.
- UserDataBox userDataBox;
- if ((userDataBox = Path.getPath(moov, "udta")) == null) {
- userDataBox = new UserDataBox();
- moov.addBox(userDataBox);
- }
- MetaBox metaBox;
- if ((metaBox = Path.getPath(userDataBox, "meta")) == null) {
- metaBox = new MetaBox();
- HandlerBox hdlr = new HandlerBox();
- hdlr.setHandlerType("mdir");
- metaBox.addBox(hdlr);
- userDataBox.addBox(metaBox);
- }
- AppleItemListBox ilst;
- if ((ilst = Path.getPath(metaBox, "ilst")) == null) {
- ilst = new AppleItemListBox();
- metaBox.addBox(ilst);
-
- }
- if (freeBox == null) {
- freeBox = new FreeBox(128 * 1024);
- metaBox.addBox(freeBox);
- }
- // Got Apple List Box
-
- AppleNameBox nam;
- if ((nam = Path.getPath(ilst, "©nam")) == null) {
- nam = new AppleNameBox();
- }
- nam.setDataCountry(0);
- nam.setDataLanguage(0);
- nam.setValue(title);
- ilst.addBox(nam);
-
- long sizeAfter = moov.getSize();
- long diff = sizeAfter - sizeBefore;
- // This is the difference of before/after
-
- // can we compensate by resizing a Free Box we have found?
- if (freeBox.getData().limit() > diff) {
- // either shrink or grow!
- freeBox.setData(ByteBuffer.allocate((int) (freeBox.getData().limit() - diff)));
- sizeAfter = moov.getSize();
- diff = sizeAfter - sizeBefore;
- }
- if (correctOffset && diff != 0) {
- correctChunkOffsets(moov, diff);
- }
- BetterByteArrayOutputStream baos = new BetterByteArrayOutputStream();
- moov.getBox(Channels.newChannel(baos));
- isoFile.close();
- FileChannel fc;
- if (diff != 0) {
- // this is not good: We have to insert bytes in the middle of the file
- // and this costs time as it requires re-writing most of the file's data
- fc = splitFileAndInsert(videoFile, offset, sizeAfter - sizeBefore);
- } else {
- // simple overwrite of something with the file
- fc = new RandomAccessFile(videoFile, "rw").getChannel();
- }
- fc.position(offset);
- fc.write(ByteBuffer.wrap(baos.getBuffer(), 0, baos.size()));
- fc.close();
- }
-
- FreeBox findFreeBox(Container c) {
- for (Box box : c.getBoxes()) {
- System.err.println(box.getType());
- if (box instanceof FreeBox) {
- return (FreeBox) box;
- }
- if (box instanceof Container) {
- FreeBox freeBox = findFreeBox((Container) box);
- if (freeBox != null) {
- return freeBox;
- }
- }
- }
- return null;
- }
-
- private void correctChunkOffsets(MovieBox movieBox, long correction) {
- List chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/stco[0]");
- if (chunkOffsetBoxes.isEmpty()) {
- chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/st64[0]");
- }
- for (ChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
- long[] cOffsets = chunkOffsetBox.getChunkOffsets();
- for (int i = 0; i < cOffsets.length; i++) {
- cOffsets[i] += correction;
- }
- }
- }
-
- private static class BetterByteArrayOutputStream extends ByteArrayOutputStream {
- byte[] getBuffer() {
- return buf;
- }
- }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/greinet/tvtotalripper/MetaDataWriter.java b/src/main/java/com/greinet/tvtotalripper/MetaDataWriter.java
index f8bca9d..343d7c6 100644
--- a/src/main/java/com/greinet/tvtotalripper/MetaDataWriter.java
+++ b/src/main/java/com/greinet/tvtotalripper/MetaDataWriter.java
@@ -1,231 +1,234 @@
-package com.greinet.tvtotalripper;
-
-
-import org.mp4parser.Box;
-import org.mp4parser.Container;
-import org.mp4parser.IsoFile;
-import org.mp4parser.boxes.apple.AppleItemListBox;
-import org.mp4parser.boxes.apple.AppleNameBox;
-import org.mp4parser.boxes.iso14496.part12.*;
-import org.mp4parser.tools.Path;
-
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.util.List;
-import org.mp4parser.boxes.apple.AppleArtistBox;
-import org.mp4parser.boxes.apple.AppleTVEpisodeBox;
-import org.mp4parser.boxes.apple.AppleTVEpisodeNumberBox;
-import org.mp4parser.boxes.apple.AppleTVSeasonBox;
-import org.mp4parser.boxes.apple.AppleTVShowBox;
-
-/**
- * Change metadata and make sure chunkoffsets are corrected.
- */
-public class MetaDataWriter {
-
- private FileChannel splitFileAndInsert(File f, long pos, long length) throws IOException {
- FileChannel read = new RandomAccessFile(f, "r").getChannel();
- File tmp = File.createTempFile("ChangeMetaData", "splitFileAndInsert");
- FileChannel tmpWrite = new RandomAccessFile(tmp, "rw").getChannel();
- read.position(pos);
- tmpWrite.transferFrom(read, 0, read.size() - pos);
- read.close();
- FileChannel write = new RandomAccessFile(f, "rw").getChannel();
- write.position(pos + length);
- tmpWrite.position(0);
- long transferred = 0;
- while ((transferred += tmpWrite.transferTo(0, tmpWrite.size() - transferred, write)) != tmpWrite.size()) {
- }
- tmpWrite.close();
- tmp.delete();
- return write;
- }
-
-
- private boolean needsOffsetCorrection(IsoFile isoFile) {
- if (Path.getPath(isoFile, "moov[0]/mvex[0]") != null) {
- // Fragmented files don't need a correction
- return false;
- } else {
- // no correction needed if mdat is before moov as insert into moov want change the offsets of mdat
- for (Box box : isoFile.getBoxes()) {
- if ("moov".equals(box.getType())) {
- return true;
- }
- if ("mdat".equals(box.getType())) {
- return false;
- }
- }
- throw new RuntimeException("I need moov or mdat. Otherwise all this doesn't make sense");
- }
- }
-
- public void writeMetadata(String videoFilePath, String title, String artist, String show, String episode) throws IOException {
-
- File videoFile = new File(videoFilePath);
- if (!videoFile.exists()) {
- throw new FileNotFoundException("File " + videoFilePath + " not exists");
- }
-
- if (!videoFile.canWrite()) {
- throw new IllegalStateException("No write permissions to file " + videoFilePath);
- }
- IsoFile isoFile = new IsoFile(videoFilePath);
-
- MovieBox moov = isoFile.getBoxes(MovieBox.class).get(0);
- FreeBox freeBox = findFreeBox(moov);
-
- boolean correctOffset = needsOffsetCorrection(isoFile);
- long sizeBefore = moov.getSize();
- long offset = 0;
- for (Box box : isoFile.getBoxes()) {
- if ("moov".equals(box.getType())) {
- break;
- }
- offset += box.getSize();
- }
-
- // Create structure or just navigate to Apple List Box.
- UserDataBox userDataBox;
- if ((userDataBox = Path.getPath(moov, "udta")) == null) {
- userDataBox = new UserDataBox();
- moov.addBox(userDataBox);
- }
- MetaBox metaBox;
- if ((metaBox = Path.getPath(userDataBox, "meta")) == null) {
- metaBox = new MetaBox();
- HandlerBox hdlr = new HandlerBox();
- hdlr.setHandlerType("mdir");
- metaBox.addBox(hdlr);
- userDataBox.addBox(metaBox);
- }
- AppleItemListBox ilst;
- if ((ilst = Path.getPath(metaBox, "ilst")) == null) {
- ilst = new AppleItemListBox();
- metaBox.addBox(ilst);
-
- }
- if (freeBox == null) {
- freeBox = new FreeBox(128 * 1024);
- metaBox.addBox(freeBox);
- }
-
- if(title != null){
- // Write the title
- AppleNameBox nam;
- if ((nam = Path.getPath(ilst, "©nam")) == null) {
- nam = new AppleNameBox();
- }
- nam.setDataCountry(0);
- nam.setDataLanguage(0);
- nam.setValue(title);
- ilst.addBox(nam);
- }
-
- if(artist!=null){
- // Write the artist
- AppleArtistBox art;
- if ((art = Path.getPath(ilst, "©ART")) == null) {
- art = new AppleArtistBox();
- }
- art.setDataCountry(0);
- art.setDataLanguage(0);
- art.setValue(artist);
- ilst.addBox(art);
- }
-
- if(episode!=null){
- // Write the episode title
- AppleTVEpisodeNumberBox ep;
- if ((ep = Path.getPath(ilst, "tven")) == null) {
- ep = new AppleTVEpisodeNumberBox();
- }
- ep.setDataCountry(0);
- ep.setDataLanguage(0);
- ep.setValue(episode);
- ilst.addBox(ep);
- }
-
- if(show!=null){
- //Write the show
- AppleTVShowBox sh;
- if ((sh = Path.getPath(ilst, "tvsh")) == null) {
- sh = new AppleTVShowBox();
- }
- sh.setDataCountry(0);
- sh.setDataLanguage(0);
- sh.setValue(show);
- ilst.addBox(sh);
- }
-
-
-
- long sizeAfter = moov.getSize();
- long diff = sizeAfter - sizeBefore;
- // This is the difference of before/after
-
- // can we compensate by resizing a Free Box we have found?
- if (freeBox.getData().limit() > diff) {
- // either shrink or grow!
- freeBox.setData(ByteBuffer.allocate((int) (freeBox.getData().limit() - diff)));
- sizeAfter = moov.getSize();
- diff = sizeAfter - sizeBefore;
- }
- if (correctOffset && diff != 0) {
- correctChunkOffsets(moov, diff);
- }
- BetterByteArrayOutputStream baos = new BetterByteArrayOutputStream();
- moov.getBox(Channels.newChannel(baos));
- isoFile.close();
- FileChannel fc;
- if (diff != 0) {
- // this is not good: We have to insert bytes in the middle of the file
- // and this costs time as it requires re-writing most of the file's data
- fc = splitFileAndInsert(videoFile, offset, sizeAfter - sizeBefore);
- } else {
- // simple overwrite of something with the file
- fc = new RandomAccessFile(videoFile, "rw").getChannel();
- }
- fc.position(offset);
- fc.write(ByteBuffer.wrap(baos.getBuffer(), 0, baos.size()));
- fc.close();
- }
-
- FreeBox findFreeBox(Container c) {
- for (Box box : c.getBoxes()) {
- if (box instanceof FreeBox) {
- return (FreeBox) box;
- }
- if (box instanceof Container) {
- FreeBox freeBox = findFreeBox((Container) box);
- if (freeBox != null) {
- return freeBox;
- }
- }
- }
- return null;
- }
-
- private void correctChunkOffsets(MovieBox movieBox, long correction) {
- List chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/stco[0]");
- if (chunkOffsetBoxes.isEmpty()) {
- chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/st64[0]");
- }
- for (ChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
- long[] cOffsets = chunkOffsetBox.getChunkOffsets();
- for (int i = 0; i < cOffsets.length; i++) {
- cOffsets[i] += correction;
- }
- }
- }
-
- private static class BetterByteArrayOutputStream extends ByteArrayOutputStream {
- byte[] getBuffer() {
- return buf;
- }
- }
-
-
+package com.greinet.tvtotalripper;
+
+import org.mp4parser.Box;
+import org.mp4parser.Container;
+import org.mp4parser.IsoFile;
+import org.mp4parser.boxes.apple.AppleItemListBox;
+import org.mp4parser.boxes.apple.AppleNameBox;
+import org.mp4parser.boxes.iso14496.part12.*;
+import org.mp4parser.tools.Path;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.util.List;
+import org.mp4parser.boxes.apple.AppleArtistBox;
+import org.mp4parser.boxes.apple.AppleTVEpisodeNumberBox;
+import org.mp4parser.boxes.apple.AppleTVShowBox;
+
+/**
+ * Utility class to change mp4 metatdata, more or less copied from https://github.com/sannies/mp4parser/blob/master/examples/src/main/java/org/mp4parser/examples/metadata/MetaDataInsert.java
+ */
+public class MetaDataWriter {
+
+ private FileChannel splitFileAndInsert(File f, long pos, long length) throws IOException {
+ FileChannel read = new RandomAccessFile(f, "r").getChannel();
+ File tmp = File.createTempFile("ChangeMetaData", "splitFileAndInsert");
+ FileChannel tmpWrite = new RandomAccessFile(tmp, "rw").getChannel();
+ read.position(pos);
+ tmpWrite.transferFrom(read, 0, read.size() - pos);
+ read.close();
+ FileChannel write = new RandomAccessFile(f, "rw").getChannel();
+ write.position(pos + length);
+ tmpWrite.position(0);
+ long transferred = 0;
+ while ((transferred += tmpWrite.transferTo(0, tmpWrite.size() - transferred, write)) != tmpWrite.size()) {
+ }
+ tmpWrite.close();
+ tmp.delete();
+ return write;
+ }
+
+ private boolean needsOffsetCorrection(IsoFile isoFile) {
+ if (Path.getPath(isoFile, "moov[0]/mvex[0]") != null) {
+ // Fragmented files don't need a correction
+ return false;
+ } else {
+ // no correction needed if mdat is before moov as insert into moov want change the offsets of mdat
+ for (Box box : isoFile.getBoxes()) {
+ if ("moov".equals(box.getType())) {
+ return true;
+ }
+ if ("mdat".equals(box.getType())) {
+ return false;
+ }
+ }
+ throw new RuntimeException("I need moov or mdat. Otherwise all this doesn't make sense");
+ }
+ }
+
+ /**
+ * Write itunes metadata to a mp4 file
+ * @param videoFilePath the file path
+ * @param title the title, or null
+ * @param artist the artist, or null
+ * @param show the show, or null
+ * @param episode the episode, or null
+ * @throws IOException error heandling mp4 file
+ */
+ public void writeMetadata(String videoFilePath, String title, String artist, String show, String episode) throws IOException {
+
+ File videoFile = new File(videoFilePath);
+ if (!videoFile.exists()) {
+ throw new FileNotFoundException("File " + videoFilePath + " not exists");
+ }
+
+ if (!videoFile.canWrite()) {
+ throw new IllegalStateException("No write permissions to file " + videoFilePath);
+ }
+ IsoFile isoFile = new IsoFile(videoFilePath);
+
+ MovieBox moov = isoFile.getBoxes(MovieBox.class).get(0);
+ FreeBox freeBox = findFreeBox(moov);
+
+ boolean correctOffset = needsOffsetCorrection(isoFile);
+ long sizeBefore = moov.getSize();
+ long offset = 0;
+ for (Box box : isoFile.getBoxes()) {
+ if ("moov".equals(box.getType())) {
+ break;
+ }
+ offset += box.getSize();
+ }
+
+ // Create structure or just navigate to Apple List Box.
+ UserDataBox userDataBox;
+ if ((userDataBox = Path.getPath(moov, "udta")) == null) {
+ userDataBox = new UserDataBox();
+ moov.addBox(userDataBox);
+ }
+ MetaBox metaBox;
+ if ((metaBox = Path.getPath(userDataBox, "meta")) == null) {
+ metaBox = new MetaBox();
+ HandlerBox hdlr = new HandlerBox();
+ hdlr.setHandlerType("mdir");
+ metaBox.addBox(hdlr);
+ userDataBox.addBox(metaBox);
+ }
+ AppleItemListBox ilst;
+ if ((ilst = Path.getPath(metaBox, "ilst")) == null) {
+ ilst = new AppleItemListBox();
+ metaBox.addBox(ilst);
+
+ }
+ if (freeBox == null) {
+ freeBox = new FreeBox(128 * 1024);
+ metaBox.addBox(freeBox);
+ }
+
+ if(title != null){
+ // Write the title
+ AppleNameBox nam;
+ if ((nam = Path.getPath(ilst, "©nam")) == null) {
+ nam = new AppleNameBox();
+ }
+ nam.setDataCountry(0);
+ nam.setDataLanguage(0);
+ nam.setValue(title);
+ ilst.addBox(nam);
+ }
+
+ if(artist!=null){
+ // Write the artist
+ AppleArtistBox art;
+ if ((art = Path.getPath(ilst, "©ART")) == null) {
+ art = new AppleArtistBox();
+ }
+ art.setDataCountry(0);
+ art.setDataLanguage(0);
+ art.setValue(artist);
+ ilst.addBox(art);
+ }
+
+ if(episode!=null){
+ // Write the episode title
+ AppleTVEpisodeNumberBox ep;
+ if ((ep = Path.getPath(ilst, "tven")) == null) {
+ ep = new AppleTVEpisodeNumberBox();
+ }
+ ep.setDataCountry(0);
+ ep.setDataLanguage(0);
+ ep.setValue(episode);
+ ilst.addBox(ep);
+ }
+
+ if(show!=null){
+ //Write the show
+ AppleTVShowBox sh;
+ if ((sh = Path.getPath(ilst, "tvsh")) == null) {
+ sh = new AppleTVShowBox();
+ }
+ sh.setDataCountry(0);
+ sh.setDataLanguage(0);
+ sh.setValue(show);
+ ilst.addBox(sh);
+ }
+
+ long sizeAfter = moov.getSize();
+ long diff = sizeAfter - sizeBefore;
+ // This is the difference of before/after
+
+ // can we compensate by resizing a Free Box we have found?
+ if (freeBox.getData().limit() > diff) {
+ // either shrink or grow!
+ freeBox.setData(ByteBuffer.allocate((int) (freeBox.getData().limit() - diff)));
+ sizeAfter = moov.getSize();
+ diff = sizeAfter - sizeBefore;
+ }
+ if (correctOffset && diff != 0) {
+ correctChunkOffsets(moov, diff);
+ }
+ BetterByteArrayOutputStream baos = new BetterByteArrayOutputStream();
+ moov.getBox(Channels.newChannel(baos));
+ isoFile.close();
+ FileChannel fc;
+ if (diff != 0) {
+ // this is not good: We have to insert bytes in the middle of the file
+ // and this costs time as it requires re-writing most of the file's data
+ fc = splitFileAndInsert(videoFile, offset, sizeAfter - sizeBefore);
+ } else {
+ // simple overwrite of something with the file
+ fc = new RandomAccessFile(videoFile, "rw").getChannel();
+ }
+ fc.position(offset);
+ fc.write(ByteBuffer.wrap(baos.getBuffer(), 0, baos.size()));
+ fc.close();
+ }
+
+ private FreeBox findFreeBox(Container c) {
+ for (Box box : c.getBoxes()) {
+ if (box instanceof FreeBox) {
+ return (FreeBox) box;
+ }
+ if (box instanceof Container) {
+ FreeBox freeBox = findFreeBox((Container) box);
+ if (freeBox != null) {
+ return freeBox;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void correctChunkOffsets(MovieBox movieBox, long correction) {
+ List chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/stco[0]");
+ if (chunkOffsetBoxes.isEmpty()) {
+ chunkOffsetBoxes = Path.getPaths((Box) movieBox, "trak/mdia[0]/minf[0]/stbl[0]/st64[0]");
+ }
+ for (ChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes) {
+ long[] cOffsets = chunkOffsetBox.getChunkOffsets();
+ for (int i = 0; i < cOffsets.length; i++) {
+ cOffsets[i] += correction;
+ }
+ }
+ }
+
+ private static class BetterByteArrayOutputStream extends ByteArrayOutputStream {
+ byte[] getBuffer() {
+ return buf;
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/src/main/java/com/greinet/tvtotalripper/SwingInterface.java b/src/main/java/com/greinet/tvtotalripper/SwingInterface.java
deleted file mode 100644
index 06884e3..0000000
--- a/src/main/java/com/greinet/tvtotalripper/SwingInterface.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.greinet.tvtotalripper;
-
-import java.awt.Dimension;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.ArrayList;
-import java.util.List;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JProgressBar;
-
-/**
- *
- * @author agreiner
- */
-public class SwingInterface implements PropertyChangeListener {
-
- private final JFrame frame;
- private final JLabel label;
- private final JProgressBar progressBar;
-
- private List changeListener = new ArrayList<>();
-
- public SwingInterface(){
-
- frame = new JFrame("TV Total Ripper");
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-
- label = new JLabel("Testlabel");
- label.setPreferredSize(new Dimension(200, 30));
-
- progressBar = new JProgressBar(0, 100);
- progressBar.setPreferredSize(new Dimension(200, 30));
- progressBar.setStringPainted(true);
-
-
- frame.add(label);
- frame.add(progressBar);
-
-
- frame.pack();
- frame.setVisible(true);
- }
-
- public static void main(String[] args) {
-
- javax.swing.SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- SwingInterface i = new SwingInterface();
- i.startDownload();
- }
- });
-
- }
-
- public void startDownload(){
- //DownloadTask task = new DownloadTask(label, "https://cldf-od.r53.cdn.tv1.eu/secdl/06d6d246daa2c7ec0ffb2f8281149072/6066001f/11021brainpool/ondemand/3583brainpool/163840/myspass2009/11/33/2171/9642/9642_61.mp4", "");
- //task.addPropertyChangeListener(this);
- //task.execute();
- }
-
-
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- if (evt.getPropertyName().equals("progress1")) {
- int progress = (Integer) evt.getNewValue();
- progressBar.setValue(progress);
- }
- }
-
-}
diff --git a/src/main/java/com/greinet/tvtotalripper/crawler/CrawlerUtil.java b/src/main/java/com/greinet/tvtotalripper/crawler/CrawlerUtil.java
index 7ee1ac9..4c7cecf 100644
--- a/src/main/java/com/greinet/tvtotalripper/crawler/CrawlerUtil.java
+++ b/src/main/java/com/greinet/tvtotalripper/crawler/CrawlerUtil.java
@@ -1,179 +1,189 @@
-package com.greinet.tvtotalripper.crawler;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.chrome.ChromeDriver;
-import org.openqa.selenium.chrome.ChromeOptions;
-import org.openqa.selenium.support.ui.ExpectedConditions;
-import org.openqa.selenium.support.ui.WebDriverWait;
-
-/**
- * Helper class to get show, season und episode elements from the website
- * @author agreiner
- */
-public class CrawlerUtil {
-
- static{
- System.setProperty("webdriver.chrome.driver", "resources/chromedriver.exe");
- }
-
- /** The logger */
- private static final Logger logger = LogManager.getLogger(CrawlerUtil.class);
- /** The WebDriver for show information */
- private final static WebDriver driverShows = createShowDriver();
- /** The WebDriver for season and episode information */
- private final static WebDriver driverSeasonsAndEpisodes = createChromeDriver();
- /** The WebDriver for fetchfile.net URL conversion */
- private final static WebDriver driverFetchFile = createFetchFileDriver();
-
- public static String show = "";
- /**
- * Create a basic ChromeDriver
- * @return
- */
- private static WebDriver createChromeDriver(){
- ChromeOptions options = new ChromeOptions();
- options.addArguments("start-maximized");
- return new ChromeDriver(options);
- }
-
- /**
- * Create the WebDriver to get show information
- * @return the WebDriver
- */
- private static WebDriver createShowDriver(){
- WebDriver driver = createChromeDriver();
- driver.get("https://www.myspass.de/sendungen-a-bis-z/");
- return driver;
- }
-
- private static WebDriver createFetchFileDriver(){
- WebDriver driver = createChromeDriver();
- driver.get("https://de.fetchfile.net/herunterladen-von-myspass");
- return driver;
- }
-
- /**
- * Navigate to the given URL or do nothing, if already at that URL
- * @param url the URL
- */
- private static void navigateToShow(String url){
- if(!driverSeasonsAndEpisodes.getCurrentUrl().equals(url)){
- driverSeasonsAndEpisodes.get(url);
- }
- driverSeasonsAndEpisodes.findElement(By.xpath("/html/body/div[4]/div[1]/div[2]/ul/li[2]/a")).click();
- }
-
- /**
- * Returns the WebElements representing the shows.
- * @return the show WebElements
- */
- public static List getShows(){
- return driverShows.findElements(By.xpath("/html/body/div[5]/div/div/div/div/a"));
- }
-
- /**
- * Returns the Webelements represeting the seasons of a specific show
- * @param url the URL to the show
- * @return the season WebElements
- */
- public static List getSeasons(String url){
- navigateToShow(url);
-
- String urlNotTrailingSlash = url.substring(0,url.lastIndexOf("/"));
-
- show = urlNotTrailingSlash.substring(urlNotTrailingSlash.lastIndexOf("/")+1, urlNotTrailingSlash.length());
- return driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[1]/select/option"));
-
- }
-
- /**
- * Returns the information from the episodes from a specific show and season packed into a wrapper class
- * @param url the URL of the show
- * @param seasonName the name of the season
- * @return the list of episodes
- */
- public static List getEpisodes(String url, String seasonName){
-
- // navigate the WebDriver to the specified URL
- navigateToShow(url);
-
- // Search the specified season
- List elements = driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[1]/select/option"));
- Optional seasonElement = elements.stream().filter(e -> e.getText().equals(seasonName)).findFirst();
-
- // If the season was found, navigate there
- if(seasonElement.isPresent()){
- seasonElement.get().click();
-
- // Wait for the website to load and then switch to the list view
- try {
- Thread.sleep(2000);
- } catch (InterruptedException ex) {
- logger.log(Level.ERROR, "Could not find list view button for url:[{0}], season:[{1}]",url, seasonName);
- }
- driverSeasonsAndEpisodes.findElement(By.className("listView--toggle_input")).click();
-
- // Get the parent div of the episode information list
- List episodeListDivs = driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div"));
- List filteredNoDisplay = episodeListDivs.stream().filter(e -> !"none".equals(e.getCssValue("display"))).collect(Collectors.toList());
-
-
- if(!filteredNoDisplay.isEmpty()){
- // Get the Webelements with the link and title information
- List linksToEpisodes = new ArrayList<>();
- filteredNoDisplay.forEach(e ->
- linksToEpisodes.addAll(e.findElements(By.xpath(".//div/table/tbody/tr/td/a")))
- );
- // Get the WebElements with the duration information
- List durationOfEpisodes = new ArrayList<>();
- filteredNoDisplay.forEach(e ->
- durationOfEpisodes.addAll(e.findElements(By.xpath(".//div/table/tbody/tr/td[3]")))
- );
- // Put the information into episode wrappers and return the list
- List wrappers = new ArrayList<>();
- for(int i=0;i();
- }
- }else{
- logger.log(Level.ERROR, "No seaons found for url:[{0}], season:[{1}]",url, seasonName);
- return new ArrayList<>();
- }
- }
-
- public static String getFetchfileURL(String myspassURL){
- synchronized(driverFetchFile){
- WebElement videoPathInput = driverFetchFile.findElement(By.id("videoPath"));
- videoPathInput.sendKeys(myspassURL);
- WebElement submitButton = driverFetchFile.findElement(By.id("home-submit"));
- submitButton.click();
- WebDriverWait wait = new WebDriverWait(driverFetchFile, 20);
- WebElement downloadButton = wait.until(ExpectedConditions.elementToBeClickable(By.className("download-link")));
- String downloadLink = downloadButton.getAttribute("href");
- driverFetchFile.get("https://de.fetchfile.net/herunterladen-von-myspass");
-
- // Close advertisement tabs
- List tabs = new ArrayList<>(driverFetchFile.getWindowHandles());
- for (int i=1;i getShows(){
+ return driverShows.findElements(By.xpath("/html/body/div[5]/div/div/div/div/a"));
+ }
+
+ /**
+ * Returns the Webelements represeting the seasons of a specific show
+ * @param url the URL to the show
+ * @return the season WebElements
+ */
+ public static List getSeasons(String url){
+ navigateToShow(url);
+
+ String urlNotTrailingSlash = url.substring(0,url.lastIndexOf("/"));
+
+ show = urlNotTrailingSlash.substring(urlNotTrailingSlash.lastIndexOf("/")+1, urlNotTrailingSlash.length());
+ return driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[1]/select/option"));
+
+ }
+
+ /**
+ * Returns the information from the episodes from a specific show and season packed into a wrapper class
+ * @param url the URL of the show
+ * @param seasonName the name of the season
+ * @return the list of episodes
+ */
+ public static List getEpisodes(String url, String seasonName){
+
+ // navigate the WebDriver to the specified URL
+ navigateToShow(url);
+
+ // Search the specified season
+ List elements = driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div[1]/select/option"));
+ Optional seasonElement = elements.stream().filter(e -> e.getText().equals(seasonName)).findFirst();
+
+ // If the season was found, navigate there
+ if(seasonElement.isPresent()){
+ seasonElement.get().click();
+
+ // Wait for the website to load and then switch to the list view
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ logger.log(Level.ERROR, "Could not find list view button for url:[{0}], season:[{1}]",url, seasonName);
+ }
+ driverSeasonsAndEpisodes.findElement(By.className("listView--toggle_input")).click();
+
+ // Get the parent div of the episode information list
+ List episodeListDivs = driverSeasonsAndEpisodes.findElements(By.xpath("/html/body/div[4]/div[1]/div[3]/div[2]/div"));
+ List filteredNoDisplay = episodeListDivs.stream().filter(e -> !"none".equals(e.getCssValue("display"))).collect(Collectors.toList());
+
+
+ if(!filteredNoDisplay.isEmpty()){
+ // Get the Webelements with the link and title information
+ List linksToEpisodes = new ArrayList<>();
+ filteredNoDisplay.forEach(e ->
+ linksToEpisodes.addAll(e.findElements(By.xpath(".//div/table/tbody/tr/td/a")))
+ );
+ // Get the WebElements with the duration information
+ List durationOfEpisodes = new ArrayList<>();
+ filteredNoDisplay.forEach(e ->
+ durationOfEpisodes.addAll(e.findElements(By.xpath(".//div/table/tbody/tr/td[3]")))
+ );
+ // Put the information into episode wrappers and return the list
+ List wrappers = new ArrayList<>();
+ for(int i=0;i();
+ }
+ }else{
+ logger.log(Level.ERROR, "No seaons found for url:[{0}], season:[{1}]",url, seasonName);
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Returns the FetchFile.net URL to the myspass.com video file
+ * @param myspassURL the URL to the myspass.com video
+ * @return the FetchFile.net URL
+ */
+ public static String getFetchfileURL(String myspassURL){
+ synchronized(driverFetchFile){
+ WebElement videoPathInput = driverFetchFile.findElement(By.id("videoPath"));
+ videoPathInput.sendKeys(myspassURL);
+ WebElement submitButton = driverFetchFile.findElement(By.id("home-submit"));
+ submitButton.click();
+ WebDriverWait wait = new WebDriverWait(driverFetchFile, 20);
+ WebElement downloadButton = wait.until(ExpectedConditions.elementToBeClickable(By.className("download-link")));
+ String downloadLink = downloadButton.getAttribute("href");
+ driverFetchFile.get("https://de.fetchfile.net/herunterladen-von-myspass");
+
+ // Close advertisement tabs
+ List tabs = new ArrayList<>(driverFetchFile.getWindowHandles());
+ for (int i=1;i 0) {
- fileName = disposition.substring(index + 10,
- disposition.length() - 1);
- }
- } else {
- // extracts file name from URL
- fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1,
- fileUrl.length());
- }
-
- // output for debugging purpose only
- System.out.println("Content-Type = " + contentType);
- System.out.println("Content-Disposition = " + disposition);
- System.out.println("Content-Length = " + contentLength);
- System.out.println("fileName = " + fileName);
-
- // opens input stream from the HTTP connection
- inputStream = httpConn.getInputStream();
-
- } else {
- throw new IOException(
- "No file to download. Server replied HTTP code: "
- + responseCode);
- }
- }
-
- public void disconnect() throws IOException {
- inputStream.close();
- httpConn.disconnect();
- }
-
- public String getFileName() {
- return this.fileName;
- }
-
- public int getContentLength() {
- return this.contentLength;
- }
-
- public InputStream getInputStream() {
- return this.inputStream;
- }
-
-}
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.greinet.tvtotalripper.download;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ *
+ * @author agreiner
+ */
+public class ConnectionUtil {
+
+ /** The connection to the download URL */
+ private HttpURLConnection httpConn;
+ /** The input stream from the connection */
+ private InputStream inputStream;
+ /** The download size */
+ private int contentLength;
+
+ /**
+ * Prepare the download connection and open the input stream
+ * @param fileUrl the URL to the file
+ * @throws IOException error preparing download
+ */
+ public void prepare(String fileUrl) throws IOException{
+ URL url = new URL(fileUrl);
+ httpConn = (HttpURLConnection) url.openConnection();
+ int responseCode = httpConn.getResponseCode();
+
+ // always check HTTP response code first
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ contentLength = httpConn.getContentLength();
+ // opens input stream from the HTTP connection
+ inputStream = httpConn.getInputStream();
+
+ } else {
+ throw new IOException(
+ "No file to download. Server replied HTTP code: "
+ + responseCode);
+ }
+ }
+
+ /**
+ * Close the inout stream and disconnect the download
+ * @throws IOException
+ */
+ public void disconnect() throws IOException {
+ inputStream.close();
+ httpConn.disconnect();
+ }
+
+ /**
+ * Get the content length of the download
+ * @return the content length
+ */
+ public int getContentLength() {
+ return this.contentLength;
+ }
+
+ /**
+ * Get the download related inout stream
+ * @return the input stream
+ */
+ public InputStream getInputStream() {
+ return this.inputStream;
+ }
+
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/download/DownloadTask.java b/src/main/java/com/greinet/tvtotalripper/download/DownloadTask.java
index edd85b8..7becf59 100644
--- a/src/main/java/com/greinet/tvtotalripper/download/DownloadTask.java
+++ b/src/main/java/com/greinet/tvtotalripper/download/DownloadTask.java
@@ -1,95 +1,130 @@
-package com.greinet.tvtotalripper.download;
-
-import com.greinet.tvtotalripper.MetaDataWriter;
-import com.greinet.tvtotalripper.crawler.CrawlerUtil;
-import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
-import com.greinet.tvtotalripper.ui.SettingsRipperPanel;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import javax.swing.SwingWorker;
-
-/**
- *
- * @author agreiner
- */
-public class DownloadTask extends SwingWorker {
- private static final int BUFFER_SIZE = 4096;
-
- private final EpisodeWrapper episodeWrapper;
-
-
- public DownloadTask(EpisodeWrapper episodeWrapper) {
- this.episodeWrapper = episodeWrapper;
- }
-
- public EpisodeWrapper getEpisodeWrapper() {
- return episodeWrapper;
- }
-
- @Override
- public String toString() {
- return episodeWrapper.getTitle();
- }
-
- public long fileSize = 0;
-
- public long totalBytesRead = 0;
-
- public int percentCompleted = 0;
-
- /**
- * Executed in background thread
- */
- @Override
- protected Void doInBackground() throws Exception {
- try {
- String downloadURL = CrawlerUtil.getFetchfileURL(episodeWrapper.getUrl());
-
- ConnectionUtil util = new ConnectionUtil();
- util.prepare(downloadURL);
-
- InputStream inputStream = util.getInputStream();
-
- String fixedTitle = episodeWrapper.getTitle().replace(":", " ");
-
- File outputFile = new File(SettingsRipperPanel.DOWNLOADFOLDER, fixedTitle+".mp4");
- FileOutputStream outputStream = new FileOutputStream(outputFile);
- byte[] buffer = new byte[BUFFER_SIZE];
- int bytesRead = -1;
- totalBytesRead = 0;
- percentCompleted = 0;
- int oldPercentCompleted = 0;
- fileSize = util.getContentLength();
-
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- totalBytesRead += bytesRead;
- percentCompleted = (int) (totalBytesRead * 100 / fileSize);
- firePropertyChange(Long.toString(episodeWrapper.getId()), oldPercentCompleted, percentCompleted);
- oldPercentCompleted = percentCompleted;
- //setProgress(percentCompleted);
- }
-
- outputStream.close();
-
- util.disconnect();
-
- MetaDataWriter mdp = new MetaDataWriter();
- mdp.writeMetadata(outputFile.getAbsolutePath(), episodeWrapper.getTitle(), episodeWrapper.getShow(), episodeWrapper.getShow(), episodeWrapper.getEpisode());
-
- } catch (IOException ex) {
- cancel(true);
- }
- return null;
- }
-
- /**
- * Executed in Swing's event dispatching thread
- */
- @Override
- protected void done() {
- firePropertyChange(Long.toString(episodeWrapper.getId()), 0, 101);
- }
-}
+package com.greinet.tvtotalripper.download;
+
+import com.greinet.tvtotalripper.crawler.CrawlerUtil;
+import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
+import com.greinet.tvtotalripper.ui.SettingsRipperPanel;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.swing.SwingWorker;
+
+/**
+ * A task representing a single file download
+ */
+public class DownloadTask extends SwingWorker {
+
+ /** The download buffer size */
+ private static final int BUFFER_SIZE = 4096;
+ /** The episode of the downloaded file */
+ private final EpisodeWrapper episodeWrapper;
+
+ /**
+ * Create a download task for a episode
+ * @param episodeWrapper
+ */
+ public DownloadTask(EpisodeWrapper episodeWrapper) {
+ this.episodeWrapper = episodeWrapper;
+ }
+
+ /**
+ * Get the episode of the download
+ * @return the episode
+ */
+ public EpisodeWrapper getEpisodeWrapper() {
+ return episodeWrapper;
+ }
+
+ @Override
+ public String toString() {
+ return episodeWrapper.getTitle();
+ }
+
+ /** The bytes size of the file to download */
+ private long fileSize = 0;
+
+ /** the amount of downloaded bytes */
+ private long totalBytesRead = 0;
+
+ /** The completion percentage */
+ private int percentCompleted = 0;
+
+ /**
+ * Executed in background thread
+ */
+ @Override
+ protected Void doInBackground() throws Exception {
+ try {
+ String downloadURL = CrawlerUtil.getFetchfileURL(episodeWrapper.getUrl());
+
+ ConnectionUtil util = new ConnectionUtil();
+ util.prepare(downloadURL);
+
+ InputStream inputStream = util.getInputStream();
+
+ String fixedTitle = episodeWrapper.getTitle().replace(":", " ");
+
+ File outputFile = new File(SettingsRipperPanel.DOWNLOADFOLDER, fixedTitle+".mp4");
+ try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bytesRead;
+ totalBytesRead = 0;
+ percentCompleted = 0;
+ int oldPercentCompleted = 0;
+ fileSize = util.getContentLength();
+
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, bytesRead);
+ totalBytesRead += bytesRead;
+ percentCompleted = (int) (totalBytesRead * 100 / fileSize);
+ firePropertyChange(Long.toString(episodeWrapper.getId()), oldPercentCompleted, percentCompleted);
+ oldPercentCompleted = percentCompleted;
+ //setProgress(percentCompleted);
+ }
+ }
+
+ util.disconnect();
+
+
+ // Enable MetaDataWriter
+ // MetaDataWriter mdp = new MetaDataWriter();
+ // mdp.writeMetadata(outputFile.getAbsolutePath(), episodeWrapper.getTitle(), episodeWrapper.getShow(), episodeWrapper.getShow(), episodeWrapper.getEpisode());
+
+ } catch (IOException ex) {
+ cancel(true);
+ }
+ return null;
+ }
+
+ /**
+ * Get the download file size in bytes
+ * @return the file size in bytes
+ */
+ public long getFileSize() {
+ return fileSize;
+ }
+
+ /**
+ * Get the amount of already downloaded bytes
+ * @return the amount of already downloaded bytes
+ */
+ public long getTotalBytesRead() {
+ return totalBytesRead;
+ }
+
+ /**
+ * Get the completiton percentage
+ * @return the completition percentage
+ */
+ public int getPercentCompleted() {
+ return percentCompleted;
+ }
+
+ /**
+ * Fire a property change event with the progress value of 101 meaning that the task is done
+ */
+ @Override
+ protected void done() {
+ firePropertyChange(Long.toString(episodeWrapper.getId()), 0, 101);
+ }
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/BaseRipperPanel.java b/src/main/java/com/greinet/tvtotalripper/ui/BaseRipperPanel.java
index cf48cc7..e11305a 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/BaseRipperPanel.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/BaseRipperPanel.java
@@ -1,116 +1,141 @@
-package com.greinet.tvtotalripper.ui;
-
-import java.awt.Color;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.event.ListSelectionEvent;
-
-/**
- *
- * @author agreiner
- */
-public class BaseRipperPanel {
-
- private final JPanel panel;
- private JList listPanel;
- private JTextField textField;
- private final JButton button;
- private final JLabel label;
- private Map elements;
-
- public BaseRipperPanel(Map elements){
- this.elements = elements;
-
- if(elements.isEmpty()){
- elements.put("Dummy-Key", "Dummy-URL");
- }
-
- panel = new JPanel(false);
- panel.setLayout(new GridBagLayout());
-
- GridBagConstraints c = new GridBagConstraints();
- c.gridx = 0;
- c.gridy = 0;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 0.75;
-
- textField = new JTextField();
- textField.setEditable(false);
- panel.add(textField,c);
-
- button = new JButton("Select");
- c.gridx = 3;
- c.gridwidth = 2;
- c.weightx = 0.25;
-
- panel.add(button,c);
-
-
- List names = new ArrayList<>(elements.keySet());
- Collections.sort(names);
-
- listPanel = new JList<>(names.toArray(new String[elements.keySet().size()]));
- JScrollPane scrollPane = new JScrollPane();
- scrollPane.setViewportView(listPanel);
- listPanel.setLayoutOrientation(JList.VERTICAL);
- listPanel.setSelectedIndex(0);
-
- listPanel.addListSelectionListener((ListSelectionEvent e) -> {
- textField.setText(listPanel.getSelectedValue());
- });
- textField.setText(listPanel.getSelectedValue());
-
- c.gridx = 0;
- c.gridy = 1;
- c.gridwidth = 5;
- c.gridheight = 5;
- c.weightx = 0;
-
- panel.add(scrollPane,c);
-
- label = new JLabel(Integer.toString(elements.keySet().size()));
- label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
-
-
- c.gridx = 4;
- c.gridy = 6;
- c.gridwidth = 1;
- c.gridheight = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.EAST;
-
- panel.add(label, c);
-
-
-
- }
-
- public JPanel getJPanel(){
- return panel;
- }
-
- public JButton getJButton(){
- return button;
- }
-
- public String getCurrentSelected(){
- return elements.get(listPanel.getSelectedValue());
- }
-
- public JList getJList(){
- return listPanel;
- }
-
-}
+package com.greinet.tvtotalripper.ui;
+
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.ListSelectionEvent;
+
+/**
+ * The base panel for show and episode visualization
+ */
+public class BaseRipperPanel {
+
+ /** The JPanel */
+ private final JPanel panel;
+ /** The Jlist for the elements */
+ private JList listPanel;
+ /** The text field for the currently selected element */
+ private JTextField textField;
+ /** The button to select the currently selected element */
+ private final JButton button;
+ /** The label for the element count */
+ private final JLabel label;
+ /** The map for the elements */
+ private final Map elements;
+
+ /**
+ * Create a base panel the display elements and select a specific one
+ * @param elements the elements
+ */
+ public BaseRipperPanel(Map elements){
+ this.elements = elements;
+
+ if(elements.isEmpty()){
+ elements.put("Dummy-Key", "Dummy-URL");
+ }
+
+ panel = new JPanel(false);
+ panel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 0.75;
+
+ textField = new JTextField();
+ textField.setEditable(false);
+ panel.add(textField,c);
+
+ button = new JButton("Select");
+ c.gridx = 3;
+ c.gridwidth = 2;
+ c.weightx = 0.25;
+
+ panel.add(button,c);
+
+
+ List names = new ArrayList<>(elements.keySet());
+ Collections.sort(names);
+
+ listPanel = new JList<>(names.toArray(new String[elements.keySet().size()]));
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setViewportView(listPanel);
+ listPanel.setLayoutOrientation(JList.VERTICAL);
+ listPanel.setSelectedIndex(0);
+
+ listPanel.addListSelectionListener((ListSelectionEvent e) -> {
+ textField.setText(listPanel.getSelectedValue());
+ });
+ textField.setText(listPanel.getSelectedValue());
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 5;
+ c.gridheight = 5;
+ c.weightx = 0;
+
+ panel.add(scrollPane,c);
+
+ label = new JLabel(Integer.toString(elements.keySet().size()));
+ label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
+
+
+ c.gridx = 4;
+ c.gridy = 6;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.EAST;
+
+ panel.add(label, c);
+
+
+
+ }
+
+ /**
+ * Get the JPanel
+ * @return the JPanel
+ */
+ public JPanel getJPanel(){
+ return panel;
+ }
+
+ /**
+ * Get the selection JButton
+ * @return the JButton
+ */
+ public JButton getJButton(){
+ return button;
+ }
+
+ /**
+ * Get the String representing the currently selected element
+ * @return the selected element
+ */
+ public String getCurrentSelected(){
+ return elements.get(listPanel.getSelectedValue());
+ }
+
+ /**
+ * Get the Jlist of the elements
+ * @return the JList
+ */
+ public JList getJList(){
+ return listPanel;
+ }
+
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/DownloadRipperPanel.java b/src/main/java/com/greinet/tvtotalripper/ui/DownloadRipperPanel.java
index a789cba..b03ba5f 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/DownloadRipperPanel.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/DownloadRipperPanel.java
@@ -1,143 +1,164 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.greinet.tvtotalripper.ui;
-
-import com.greinet.tvtotalripper.download.DownloadTask;
-import java.awt.Color;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import javax.swing.BorderFactory;
-import javax.swing.DefaultListModel;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-
-/**
- *
- * @author agreiner
- */
-public class DownloadRipperPanel implements PropertyChangeListener{
-
- private final JPanel panel;
- private JList listTasks;
- private DefaultListModel listModel;
- private JTextField textSelectedTask;
- private final JLabel labelTaskCount;
-
- private final List downloadTasks;
-
- private DownloadTaskInformationPanel infoPanel;
-
- public DownloadRipperPanel(){
-
- downloadTasks = new ArrayList<>();
-
- panel = new JPanel();
- panel.setLayout(new GridBagLayout());
-
- GridBagConstraints c = new GridBagConstraints();
-
- c.gridx = 0;
- c.gridy = 0;
- c.gridwidth = 5;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 0.5;
- textSelectedTask = new JTextField();
- textSelectedTask.setEditable(false);
- panel.add(textSelectedTask, c);
-
-
- listModel = new DefaultListModel<>();
- listTasks = new JList<>(listModel);
- listTasks.setSelectedIndex(ListSelectionModel.SINGLE_SELECTION);
- JScrollPane scrollPane = new JScrollPane();
- scrollPane.setViewportView(listTasks);
- listTasks.setLayoutOrientation(JList.VERTICAL);
-
- c.gridx = 0;
- c.gridy = 1;
- c.gridwidth = 5;
- c.gridheight = 5;
- c.weightx = 0.5;
- panel.add(scrollPane, c);
-
- infoPanel = new DownloadTaskInformationPanel();
- c.gridx = 5;
- c.gridy = 0;
- c.gridwidth = 5;
- c.weightx = 0.5;
- c.fill = GridBagConstraints.BOTH;
- panel.add(infoPanel, c);
-
- listTasks.addListSelectionListener((ListSelectionEvent e) -> {
- if(listTasks.getSelectedValue()!=null){
- textSelectedTask.setText(listTasks.getSelectedValue().toString());
- infoPanel.setInformation(listTasks.getSelectedValue());
- infoPanel.selectedDownloadTask = listTasks.getSelectedValue();
- }
- });
-
-
- labelTaskCount = new JLabel(Integer.toString(listTasks.getModel().getSize()));
- labelTaskCount.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
-
- c.gridx = 4;
- c.gridy = 6;
- c.gridwidth = 1;
- c.gridheight = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.EAST;
- panel.add(labelTaskCount, c);
- }
-
- public JPanel getJPanel(){
- return panel;
- }
-
- public DownloadTask getSelectedTask(){
- return listTasks.getSelectedValue();
- }
-
- public void addTask(DownloadTask task){
- downloadTasks.add(task);
- task.execute();
- listModel.addElement(task);
- updateTaskCount();
- task.addPropertyChangeListener(this);
- }
-
-
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- if(evt.getNewValue().equals(101)){
- Optional taskToRemove = downloadTasks.stream().filter(t -> Long.toString(t.getEpisodeWrapper().getId()).equals(evt.getPropertyName())).findFirst();
- if(taskToRemove.isPresent()){
- if(listTasks.getSelectedValue() != null && taskToRemove.get().equals(listTasks.getSelectedValue())){
- infoPanel.clearInformation();
- textSelectedTask.setText("");
- }
- downloadTasks.remove(taskToRemove.get());
- listModel.removeElement(taskToRemove.get());
- updateTaskCount();
-
- }
- }
- panel.repaint();
- }
-
- private void updateTaskCount(){
- labelTaskCount.setText(Integer.toString(listTasks.getModel().getSize()));
- }
-}
+package com.greinet.tvtotalripper.ui;
+
+import com.greinet.tvtotalripper.download.DownloadTask;
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+
+/**
+ * A download panel to show the current downloads
+ */
+public class DownloadRipperPanel implements PropertyChangeListener{
+
+ /** The JPanel for download task visualization */
+ private final JPanel panel;
+ /** The JList for the downloads */
+ private JList listTasks;
+ /** The ListModel for the DownloadTasks */
+ private final DefaultListModel listModel;
+ /** The text field for the currently selected task */
+ private JTextField textSelectedTask;
+ /** The JLabel for the DownloadTask count */
+ private final JLabel labelTaskCount;
+ /** The list of download tasks */
+ private final List downloadTasks;
+ /** The information panel for the currently selected task */
+ private DownloadTaskInformationPanel infoPanel;
+
+ /**
+ * Create a download panel
+ */
+ public DownloadRipperPanel(){
+
+ downloadTasks = new ArrayList<>();
+
+ panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 5;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 0.5;
+ textSelectedTask = new JTextField();
+ textSelectedTask.setEditable(false);
+ panel.add(textSelectedTask, c);
+
+
+ listModel = new DefaultListModel<>();
+ listTasks = new JList<>(listModel);
+ listTasks.setSelectedIndex(ListSelectionModel.SINGLE_SELECTION);
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setViewportView(listTasks);
+ listTasks.setLayoutOrientation(JList.VERTICAL);
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 5;
+ c.gridheight = 5;
+ c.weightx = 0.5;
+ panel.add(scrollPane, c);
+
+ infoPanel = new DownloadTaskInformationPanel();
+ c.gridx = 5;
+ c.gridy = 0;
+ c.gridwidth = 5;
+ c.weightx = 0.5;
+ c.fill = GridBagConstraints.BOTH;
+ panel.add(infoPanel, c);
+
+ listTasks.addListSelectionListener((ListSelectionEvent e) -> {
+ if(listTasks.getSelectedValue()!=null){
+ textSelectedTask.setText(listTasks.getSelectedValue().toString());
+ infoPanel.setInformation(listTasks.getSelectedValue());
+ infoPanel.selectedDownloadTask = listTasks.getSelectedValue();
+ }
+ });
+
+
+ labelTaskCount = new JLabel(Integer.toString(listTasks.getModel().getSize()));
+ labelTaskCount.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
+
+ c.gridx = 4;
+ c.gridy = 6;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.EAST;
+ panel.add(labelTaskCount, c);
+ }
+
+ /**
+ * Get the JPanel
+ * @return the JPanel
+ */
+ public JPanel getJPanel(){
+ return panel;
+ }
+
+ /**
+ * Get the currently selected task
+ * @return the selected task
+ */
+ public DownloadTask getSelectedTask(){
+ return listTasks.getSelectedValue();
+ }
+
+ /**
+ * Add a download task to be executed
+ * @param task
+ */
+ public void addTask(DownloadTask task){
+ downloadTasks.add(task);
+ task.execute();
+ listModel.addElement(task);
+ updateTaskCount();
+ task.addPropertyChangeListener(this);
+ }
+
+
+ /**
+ * Listen to the property change events and remove a task if the new value is 101
+ * @param evt the event parameters
+ */
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if(evt.getNewValue().equals(101)){
+ Optional taskToRemove = downloadTasks.stream().filter(t -> Long.toString(t.getEpisodeWrapper().getId()).equals(evt.getPropertyName())).findFirst();
+ if(taskToRemove.isPresent()){
+ if(listTasks.getSelectedValue() != null && taskToRemove.get().equals(listTasks.getSelectedValue())){
+ infoPanel.clearInformation();
+ textSelectedTask.setText("");
+ }
+ downloadTasks.remove(taskToRemove.get());
+ listModel.removeElement(taskToRemove.get());
+ updateTaskCount();
+
+ }
+ }
+ panel.repaint();
+ }
+
+ /**
+ * Update the current task count
+ */
+ private void updateTaskCount(){
+ labelTaskCount.setText(Integer.toString(listTasks.getModel().getSize()));
+ }
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/DownloadTaskInformationPanel.java b/src/main/java/com/greinet/tvtotalripper/ui/DownloadTaskInformationPanel.java
index c0f4ca2..2f09d3a 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/DownloadTaskInformationPanel.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/DownloadTaskInformationPanel.java
@@ -1,126 +1,147 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.greinet.tvtotalripper.ui;
-
-import com.greinet.tvtotalripper.download.DownloadTask;
-import java.awt.GridLayout;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.JTextField;
-import org.apache.commons.io.FileUtils;
-
-/**
- *
- * @author agreiner
- */
-public class DownloadTaskInformationPanel extends JPanel{
-
- private JLabel labelTitle;
- private JLabel labelShow;
- private JLabel labelSeason;
- private JLabel labelEpisode;
- private JLabel labelDuration;
- private JLabel labelProgress;
-
- private JTextField textTitle;
- private JTextField textShow;
- private JTextField textSeason;
- private JTextField textEpisode;
- private JTextField textDuration;
- private JProgressBar progressBar;
-
- public DownloadTask selectedDownloadTask;
-
- public DownloadTaskInformationPanel(){
-
- labelTitle = new JLabel("Title");
- labelShow = new JLabel("Show");
- labelSeason = new JLabel("Season");
- labelEpisode = new JLabel("Episode");
- labelDuration = new JLabel("Duration");
- labelProgress = new JLabel("Progress");
-
- textTitle = new JTextField();
- textTitle.setEditable(false);
-
- textShow = new JTextField();
- textShow.setEditable(false);
-
- textSeason = new JTextField();
- textSeason.setEditable(false);
-
- textEpisode = new JTextField();
- textEpisode.setEditable(false);
-
- textDuration = new JTextField();
- textDuration.setEditable(false);
-
- progressBar = new JProgressBar(0, 100);
-
- setLayout(new GridLayout(6, 2));
-
- add(labelTitle);
- add(textTitle);
- add(labelShow);
- add(textShow);
- add(labelSeason);
- add(textSeason);
- add(labelEpisode);
- add(textEpisode);
- add(labelDuration);
- add(textDuration);
- add(labelProgress);
- add(progressBar);
- }
-
- public void clearInformation(){
- this.selectedDownloadTask = null;
- textTitle.setText("");
- textShow.setText("");
- textSeason.setText("");
- textEpisode.setText("");
- textDuration.setText("");
- progressBar.setValue(0);
- progressBar.setString("");
- }
-
- public void setInformation(DownloadTask downloadTask){
- textTitle.setText(downloadTask.getEpisodeWrapper().getTitle());
- textTitle.setEditable(false);
- textShow.setText(downloadTask.getEpisodeWrapper().getShow());
- textShow.setEditable(false);
- textSeason.setText(downloadTask.getEpisodeWrapper().getSeason());
- textSeason.setEditable(false);
- textEpisode.setText(downloadTask.getEpisodeWrapper().getEpisode());
- textEpisode.setEditable(false);
- textDuration.setText(downloadTask.getEpisodeWrapper().getDuration());
-
- if(selectedDownloadTask != null && selectedDownloadTask.equals(downloadTask)){
- progressBar.setValue(downloadTask.percentCompleted);
- progressBar.setStringPainted(true);
- String done = FileUtils.byteCountToDisplaySize(downloadTask.totalBytesRead);
- String todo = FileUtils.byteCountToDisplaySize(downloadTask.fileSize);
- progressBar.setString(done+"/"+todo);
- }
-
- downloadTask.addPropertyChangeListener((PropertyChangeEvent evt) -> {
-
- if(selectedDownloadTask != null && evt.getPropertyName().equals(Long.toString(selectedDownloadTask.getEpisodeWrapper().getId()))){
- progressBar.setValue((int)evt.getNewValue());
- progressBar.setStringPainted(true);
- String done = FileUtils.byteCountToDisplaySize(downloadTask.totalBytesRead);
- String todo = FileUtils.byteCountToDisplaySize(downloadTask.fileSize);
- progressBar.setString(done+"/"+todo);
- }
- });
- }
-
-
-
-}
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.greinet.tvtotalripper.ui;
+
+import com.greinet.tvtotalripper.download.DownloadTask;
+import java.awt.GridLayout;
+import java.beans.PropertyChangeEvent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import org.apache.commons.io.FileUtils;
+
+/**
+ *
+ * @author agreiner
+ */
+public class DownloadTaskInformationPanel extends JPanel{
+
+ /** The label for the title */
+ private final JLabel labelTitle;
+ /** The label for the show */
+ private final JLabel labelShow;
+ /** The label for the season */
+ private final JLabel labelSeason;
+ /** The label for the episode */
+ private final JLabel labelEpisode;
+ /** The label for the duration */
+ private final JLabel labelDuration;
+ /** The label for the download progress */
+ private final JLabel labelProgress;
+ /** The text field for the title */
+ private final JTextField textTitle;
+ /** The text field for the show */
+ private final JTextField textShow;
+ /** The text field for the season */
+ private final JTextField textSeason;
+ /** The text field for the episode */
+ private final JTextField textEpisode;
+ /** The text field for the duration */
+ private final JTextField textDuration;
+ /** The text field for the download progress */
+ private final JProgressBar progressBar;
+
+ /** The currently visualized download task */
+ public DownloadTask selectedDownloadTask;
+
+ /**
+ * Create a Panel for DownloadTask information visualization
+ */
+ public DownloadTaskInformationPanel(){
+
+ labelTitle = new JLabel("Title");
+ labelShow = new JLabel("Show");
+ labelSeason = new JLabel("Season");
+ labelEpisode = new JLabel("Episode");
+ labelDuration = new JLabel("Duration");
+ labelProgress = new JLabel("Progress");
+
+ textTitle = new JTextField();
+ textTitle.setEditable(false);
+
+ textShow = new JTextField();
+ textShow.setEditable(false);
+
+ textSeason = new JTextField();
+ textSeason.setEditable(false);
+
+ textEpisode = new JTextField();
+ textEpisode.setEditable(false);
+
+ textDuration = new JTextField();
+ textDuration.setEditable(false);
+
+ progressBar = new JProgressBar(0, 100);
+
+ setLayout(new GridLayout(6, 2));
+
+ add(labelTitle);
+ add(textTitle);
+ add(labelShow);
+ add(textShow);
+ add(labelSeason);
+ add(textSeason);
+ add(labelEpisode);
+ add(textEpisode);
+ add(labelDuration);
+ add(textDuration);
+ add(labelProgress);
+ add(progressBar);
+ }
+
+ /**
+ * Clear all information
+ */
+ public void clearInformation(){
+ this.selectedDownloadTask = null;
+ textTitle.setText("");
+ textShow.setText("");
+ textSeason.setText("");
+ textEpisode.setText("");
+ textDuration.setText("");
+ progressBar.setValue(0);
+ progressBar.setString("");
+ }
+
+ /**
+ * Set the information of the download task
+ * @param downloadTask the download task
+ */
+ public void setInformation(DownloadTask downloadTask){
+ textTitle.setText(downloadTask.getEpisodeWrapper().getTitle());
+ textTitle.setEditable(false);
+ textShow.setText(downloadTask.getEpisodeWrapper().getShow());
+ textShow.setEditable(false);
+ textSeason.setText(downloadTask.getEpisodeWrapper().getSeason());
+ textSeason.setEditable(false);
+ textEpisode.setText(downloadTask.getEpisodeWrapper().getEpisode());
+ textEpisode.setEditable(false);
+ textDuration.setText(downloadTask.getEpisodeWrapper().getDuration());
+
+ if(selectedDownloadTask != null && selectedDownloadTask.equals(downloadTask)){
+ progressBar.setValue(downloadTask.getPercentCompleted());
+ progressBar.setStringPainted(true);
+ String done = FileUtils.byteCountToDisplaySize(downloadTask.getTotalBytesRead());
+ String todo = FileUtils.byteCountToDisplaySize(downloadTask.getFileSize());
+ progressBar.setString(done+"/"+todo);
+ }
+
+ downloadTask.addPropertyChangeListener((PropertyChangeEvent evt) -> {
+
+ if(selectedDownloadTask != null && evt.getPropertyName().equals(Long.toString(selectedDownloadTask.getEpisodeWrapper().getId()))){
+ progressBar.setValue((int)evt.getNewValue());
+ progressBar.setStringPainted(true);
+ String done = FileUtils.byteCountToDisplaySize(downloadTask.getTotalBytesRead());
+ String todo = FileUtils.byteCountToDisplaySize(downloadTask.getFileSize());
+ progressBar.setString(done+"/"+todo);
+ }
+ });
+ }
+
+
+
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/EpisodesRipperPanel.java b/src/main/java/com/greinet/tvtotalripper/ui/EpisodesRipperPanel.java
index 9a3cf63..b5b1111 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/EpisodesRipperPanel.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/EpisodesRipperPanel.java
@@ -1,124 +1,146 @@
-package com.greinet.tvtotalripper.ui;
-
-import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
-import java.awt.Color;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.util.List;
-import javax.swing.BorderFactory;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.event.ListSelectionEvent;
-
-/**
- *
- * @author agreiner
- */
-public class EpisodesRipperPanel {
-
- private final JPanel panel;
-
- private JList listPanel;
- private DefaultListModel listModel;
-
- private JTextField textField;
- private final JButton buttonDownload;
- private final JLabel label;
- private final List episodes;
-
- private final JButton buttonDownloadAll;
-
- public EpisodesRipperPanel(List episodes){
- this.episodes = episodes;
-
- panel = new JPanel(false);
- panel.setLayout(new GridBagLayout());
-
- GridBagConstraints c = new GridBagConstraints();
- c.gridx = 0;
- c.gridy = 0;
- c.gridwidth = 3;
- c.fill = GridBagConstraints.BOTH;
- c.weightx = 0.4;
-
- textField = new JTextField();
- textField.setEditable(false);
- panel.add(textField,c);
-
- buttonDownload = new JButton("Download");
- c.gridx = 3;
- c.gridwidth = 2;
- c.weightx = 0.1;
-
- panel.add(buttonDownload,c);
-
- listModel = new DefaultListModel<>();
- episodes.forEach(e -> listModel.addElement(e));
-
- listPanel = new JList<>(listModel);
- JScrollPane scrollPane = new JScrollPane();
- scrollPane.setViewportView(listPanel);
- listPanel.setLayoutOrientation(JList.VERTICAL);
- listPanel.setSelectedIndex(0);
-
- listPanel.addListSelectionListener((ListSelectionEvent e) -> {
- textField.setText(listPanel.getSelectedValue().toString());
- });
- textField.setText(listPanel.getSelectedValue().toString());
-
- c.gridx = 0;
- c.gridy = 1;
- c.gridwidth = 5;
- c.gridheight = 5;
- c.weightx = 0.5;
-
- panel.add(scrollPane,c);
-
- label = new JLabel(Integer.toString(episodes.size()));
- label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
-
- buttonDownloadAll = new JButton("Download all episodes");
- c.gridx = 6;
- c.gridy = 0;
- c.gridwidth = 1;
- c.gridheight = 6;
- c.weightx = 0.5;
- panel.add(buttonDownloadAll,c);
-
-
-
- c.gridx = 4;
- c.gridy = 6;
- c.gridwidth = 1;
- c.gridheight = 1;
- c.fill = GridBagConstraints.NONE;
- c.anchor = GridBagConstraints.EAST;
-
- panel.add(label, c);
-
-
-
- }
-
- public JPanel getJPanel(){
- return panel;
- }
-
- public EpisodeWrapper getCurrentSelected(){
- return listPanel.getSelectedValue();
- }
-
- public JButton getDownloadButton(){
- return buttonDownload;
- }
-
- public JButton getDownloadAllButton(){
- return buttonDownloadAll;
- }
-
-}
+package com.greinet.tvtotalripper.ui;
+
+import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.List;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.event.ListSelectionEvent;
+
+/**
+ * A panel to display the episodes of a season
+ */
+public class EpisodesRipperPanel {
+ /** The JPanel */
+ private final JPanel panel;
+ /** The list for the episodes */
+ private JList listPanel;
+ /** The list model for the episode list */
+ private DefaultListModel listModel;
+ /** The text field for the currently selected episode */
+ private JTextField textField;
+ /** The button to start the episode download */
+ private final JButton buttonDownload;
+ /** The label for the episode count */
+ private final JLabel label;
+ /** The list of episodes */
+ private final List episodes;
+ /** The button to download all episodes in the list */
+ private final JButton buttonDownloadAll;
+
+ /**
+ * Create a panel to display episodes in a list
+ * @param episodes the episodes to display
+ */
+ public EpisodesRipperPanel(List episodes){
+ this.episodes = episodes;
+
+ panel = new JPanel(false);
+ panel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 3;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 0.4;
+
+ textField = new JTextField();
+ textField.setEditable(false);
+ panel.add(textField,c);
+
+ buttonDownload = new JButton("Download");
+ c.gridx = 3;
+ c.gridwidth = 2;
+ c.weightx = 0.1;
+
+ panel.add(buttonDownload,c);
+
+ listModel = new DefaultListModel<>();
+ episodes.forEach(e -> listModel.addElement(e));
+
+ listPanel = new JList<>(listModel);
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setViewportView(listPanel);
+ listPanel.setLayoutOrientation(JList.VERTICAL);
+ listPanel.setSelectedIndex(0);
+
+ listPanel.addListSelectionListener((ListSelectionEvent e) -> {
+ textField.setText(listPanel.getSelectedValue().toString());
+ });
+ textField.setText(listPanel.getSelectedValue().toString());
+
+ c.gridx = 0;
+ c.gridy = 1;
+ c.gridwidth = 5;
+ c.gridheight = 5;
+ c.weightx = 0.5;
+
+ panel.add(scrollPane,c);
+
+ label = new JLabel(Integer.toString(episodes.size()));
+ label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
+
+ buttonDownloadAll = new JButton("Download all episodes");
+ c.gridx = 6;
+ c.gridy = 0;
+ c.gridwidth = 1;
+ c.gridheight = 6;
+ c.weightx = 0.5;
+ panel.add(buttonDownloadAll,c);
+
+
+
+ c.gridx = 4;
+ c.gridy = 6;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.EAST;
+
+ panel.add(label, c);
+
+
+
+ }
+ /**
+ * Get the JPanel
+ * @return the JPanel
+ */
+ public JPanel getJPanel(){
+ return panel;
+ }
+
+ /**
+ * Get the currently selecte episode
+ * @return
+ */
+ public EpisodeWrapper getCurrentSelected(){
+ return listPanel.getSelectedValue();
+ }
+
+ /**
+ * Get the download button
+ * @return the download button
+ */
+ public JButton getDownloadButton(){
+ return buttonDownload;
+ }
+
+ /**
+ * Get the download all button
+ * @return the download all button
+ */
+ public JButton getDownloadAllButton(){
+ return buttonDownloadAll;
+ }
+
+}
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/RipperWindow.java b/src/main/java/com/greinet/tvtotalripper/ui/RipperWindow.java
index 838cf46..479387f 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/RipperWindow.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/RipperWindow.java
@@ -1,132 +1,153 @@
-package com.greinet.tvtotalripper.ui;
-
-import com.greinet.tvtotalripper.crawler.CrawlerUtil;
-import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
-import com.greinet.tvtotalripper.download.DownloadTask;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.swing.JComponent;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebElement;
-
-/**
- *
- * @author agreiner
- */
-public class RipperWindow {
-
- private final JFrame frame;
- private final JTabbedPane tabbedPane;
-
- private JComponent panel1;
- private JComponent panel2;
- private JComponent panel3;
- private JComponent panel4;
- private JComponent panel5;
-
- private BaseRipperPanel showRipperPanel;
- private SettingsRipperPanel srp;
- private DownloadRipperPanel drp;
-
- public RipperWindow(){
- frame = new JFrame("TV Total Ripper");
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-
- tabbedPane = new JTabbedPane();
-
- showRipperPanel = createShowsPanel();
- srp = new SettingsRipperPanel();
- drp = new DownloadRipperPanel();
-
- panel1 = showRipperPanel.getJPanel();
- panel2 = new JPanel();
- panel3 = new JPanel();
- panel4 = drp.getJPanel();
- panel5 = srp.getPanel();
-
- tabbedPane.addTab("Shows", panel1);
- tabbedPane.addTab("Seasons", panel2);
- tabbedPane.addTab("Episodes", panel3);
- tabbedPane.addTab("Downloads", panel4);
- tabbedPane.addTab("Settings", panel5);
-
- tabbedPane.setEnabledAt(1, false);
- tabbedPane.setEnabledAt(2, false);
-
- tabbedPane.setPreferredSize(new Dimension(900, 400));
-
- frame.add(tabbedPane);
-
- frame.pack();
- frame.setAlwaysOnTop(true);
- frame.setVisible(true);
- }
-
- public static void main(String[] args) {
- RipperWindow ripperWindow = new RipperWindow();
- }
-
- private BaseRipperPanel createShowsPanel(){
- List shows = CrawlerUtil.getShows();
- Map namesToUrls = shows.stream().collect(Collectors.toMap(e -> e.findElement(By.xpath(".//img")).getAttribute("alt") , e -> e.getAttribute("href")));
-
- BaseRipperPanel brp = new BaseRipperPanel(namesToUrls);
-
- brp.getJButton().addActionListener((ActionEvent e) -> {
- panel3 = new JPanel();
- tabbedPane.setEnabledAt(2, false);
- panel1 = createSeasonsPanel(brp.getCurrentSelected()).getJPanel();
- tabbedPane.setComponentAt(1, panel1);
- tabbedPane.setEnabledAt(1, true);
- tabbedPane.setSelectedIndex(1);
- });
-
- return brp;
- }
-
- private BaseRipperPanel createSeasonsPanel(String url){
- List seasons = CrawlerUtil.getSeasons(url);
- Map elements = seasons.stream().collect(Collectors.toMap(e -> e.getText(), e -> e.getText()));
-
- BaseRipperPanel brp = new BaseRipperPanel(elements);
-
- brp.getJButton().addActionListener((ActionEvent e) -> {
- tabbedPane.setEnabledAt(2, false);
- panel2 = createEpisodesPanel(url,brp.getCurrentSelected()).getJPanel();
- tabbedPane.setComponentAt(2, panel2);
- tabbedPane.setEnabledAt(2, true);
- tabbedPane.setSelectedIndex(2);
- });
-
- return brp;
- }
-
- private EpisodesRipperPanel createEpisodesPanel(String url, String seasonName){
- List episodes = CrawlerUtil.getEpisodes(url, seasonName);
-
- EpisodesRipperPanel erp = new EpisodesRipperPanel(episodes);
-
- erp.getDownloadButton().addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- drp.addTask(new DownloadTask(erp.getCurrentSelected()));
- }
- });
-
- erp.getDownloadAllButton().addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- episodes.forEach(d -> drp.addTask(new DownloadTask(d)));
- }
- });
- return erp;
- }
-
+package com.greinet.tvtotalripper.ui;
+
+import com.greinet.tvtotalripper.crawler.CrawlerUtil;
+import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
+import com.greinet.tvtotalripper.download.DownloadTask;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+/**
+ *
+ * @author agreiner
+ */
+public class RipperWindow {
+ /** The pane managing the tabs */
+ private final JTabbedPane tabbedPane;
+ /** The panel for the shows */
+ private JComponent panel1;
+ /** The panel for the seasons */
+ private JComponent panel2;
+ /** The panel for the episodes */
+ private JComponent panel3;
+ /** The panel for the downloads */
+ private final JComponent panel4;
+ /** The panel for the settings */
+ private final JComponent panel5;
+ /** The show panel */
+ private final BaseRipperPanel showRipperPanel;
+ /** The settings panel */
+ private final SettingsRipperPanel srp;
+ /** The downloads panel */
+ private final DownloadRipperPanel drp;
+
+ /**
+ * Create the main application UI
+ */
+ public RipperWindow(){
+ JFrame frame = new JFrame("TV Total Ripper");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ tabbedPane = new JTabbedPane();
+
+ showRipperPanel = createShowsPanel();
+ srp = new SettingsRipperPanel();
+ drp = new DownloadRipperPanel();
+
+ panel1 = showRipperPanel.getJPanel();
+ panel2 = new JPanel();
+ panel3 = new JPanel();
+ panel4 = drp.getJPanel();
+ panel5 = srp.getPanel();
+
+ tabbedPane.addTab("Shows", panel1);
+ tabbedPane.addTab("Seasons", panel2);
+ tabbedPane.addTab("Episodes", panel3);
+ tabbedPane.addTab("Downloads", panel4);
+ tabbedPane.addTab("Settings", panel5);
+
+ tabbedPane.setEnabledAt(1, false);
+ tabbedPane.setEnabledAt(2, false);
+
+ tabbedPane.setPreferredSize(new Dimension(900, 400));
+
+ frame.add(tabbedPane);
+
+ frame.pack();
+ frame.setAlwaysOnTop(true);
+ frame.setVisible(true);
+ }
+
+ /**
+ * The main method to start the program
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ RipperWindow ripperWindow = new RipperWindow();
+ }
+
+ /**
+ * Create a show panel listing all available shows
+ * @return the shopw panel
+ */
+ private BaseRipperPanel createShowsPanel(){
+ List shows = CrawlerUtil.getShows();
+ Map namesToUrls = shows.stream().collect(Collectors.toMap(e -> e.findElement(By.xpath(".//img")).getAttribute("alt") , e -> e.getAttribute("href")));
+
+ BaseRipperPanel brp = new BaseRipperPanel(namesToUrls);
+
+ brp.getJButton().addActionListener((ActionEvent e) -> {
+ panel3 = new JPanel();
+ tabbedPane.setEnabledAt(2, false);
+ panel1 = createSeasonsPanel(brp.getCurrentSelected()).getJPanel();
+ tabbedPane.setComponentAt(1, panel1);
+ tabbedPane.setEnabledAt(1, true);
+ tabbedPane.setSelectedIndex(1);
+ });
+
+ return brp;
+ }
+
+ /**
+ * Create a seaon panel for a selected show
+ * @param url the URL to the show
+ * @return the season panel
+ */
+ private BaseRipperPanel createSeasonsPanel(String url){
+ List seasons = CrawlerUtil.getSeasons(url);
+ Map elements = seasons.stream().collect(Collectors.toMap(e -> e.getText(), e -> e.getText()));
+
+ BaseRipperPanel brp = new BaseRipperPanel(elements);
+
+ brp.getJButton().addActionListener((ActionEvent e) -> {
+ tabbedPane.setEnabledAt(2, false);
+ panel2 = createEpisodesPanel(url,brp.getCurrentSelected()).getJPanel();
+ tabbedPane.setComponentAt(2, panel2);
+ tabbedPane.setEnabledAt(2, true);
+ tabbedPane.setSelectedIndex(2);
+ });
+
+ return brp;
+ }
+
+ /**
+ * Create a episode panel
+ * @param url the URL to the episode list
+ * @param seasonName the name of the selected season
+ * @return the episode panel
+ */
+ private EpisodesRipperPanel createEpisodesPanel(String url, String seasonName){
+ List episodes = CrawlerUtil.getEpisodes(url, seasonName);
+
+ EpisodesRipperPanel erp = new EpisodesRipperPanel(episodes);
+
+ erp.getDownloadButton().addActionListener((ActionEvent e) -> {
+ drp.addTask(new DownloadTask(erp.getCurrentSelected()));
+ });
+
+ erp.getDownloadAllButton().addActionListener((ActionEvent e) -> {
+ episodes.forEach(d -> drp.addTask(new DownloadTask(d)));
+ });
+ return erp;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/greinet/tvtotalripper/ui/SettingsRipperPanel.java b/src/main/java/com/greinet/tvtotalripper/ui/SettingsRipperPanel.java
index 63e35da..7653799 100644
--- a/src/main/java/com/greinet/tvtotalripper/ui/SettingsRipperPanel.java
+++ b/src/main/java/com/greinet/tvtotalripper/ui/SettingsRipperPanel.java
@@ -1,90 +1,97 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.greinet.tvtotalripper.ui;
-
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.io.File;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-
-/**
- *
- * @author agreiner
- */
-public class SettingsRipperPanel {
-
- private JPanel panel;
- private JLabel labelDownloadFolder;
- private JTextField textDownloadFolder;
- private JFileChooser fileChooserDownloadFolder;
- public static File DOWNLOADFOLDER = new File(".");
- private JButton button;
-
- public SettingsRipperPanel(){
- panel = new JPanel();
- panel.setLayout(new GridBagLayout());
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.anchor = GridBagConstraints.NORTHWEST;
-
- gbc.gridx=0;
- gbc.gridy=0;
- gbc.gridwidth=1;
- gbc.insets.bottom = 10;
- labelDownloadFolder = new JLabel("Download folder");
- labelDownloadFolder.setFont(new Font(labelDownloadFolder.getFont().getFontName(), Font.BOLD, 15));
- panel.add(labelDownloadFolder, gbc);
-
- gbc.gridx=0;
- gbc.gridy=1;
- gbc.gridwidth=8;
- gbc.insets.left = 20;
- textDownloadFolder = new JTextField(DOWNLOADFOLDER.getAbsolutePath());
- textDownloadFolder.setEditable(false);
- textDownloadFolder.setPreferredSize(new Dimension(500, 30));
- panel.add(textDownloadFolder,gbc);
-
-
-
-
-
- gbc.gridx=8;
- gbc.gridy=1;
- gbc.gridwidth=1;
- gbc.insets.left = 0;
- button = new JButton("...");
- panel.add(button,gbc);
-
- fileChooserDownloadFolder = new JFileChooser(DOWNLOADFOLDER);
- fileChooserDownloadFolder.setDialogTitle("Select download folder");
- fileChooserDownloadFolder.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- fileChooserDownloadFolder.setAcceptAllFileFilterUsed(false);
-
-
- button.addActionListener(e -> {
- int value = fileChooserDownloadFolder.showOpenDialog(panel);
-
- if (value == JFileChooser.APPROVE_OPTION){
- DOWNLOADFOLDER = fileChooserDownloadFolder.getSelectedFile();
- textDownloadFolder.setText(DOWNLOADFOLDER.getAbsolutePath());
- }
-
- });
- }
-
- public JPanel getPanel() {
- return panel;
- }
-
-
-
-}
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.greinet.tvtotalripper.ui;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.io.File;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+/**
+ *
+ * @author agreiner
+ */
+public class SettingsRipperPanel {
+
+ /** The JPanel to visualize the settings */
+ private JPanel panel;
+ /** The JLabel for the download folder selection */
+ private final JLabel labelDownloadFolder;
+ /** The text field for the current download folder */
+ private JTextField textDownloadFolder;
+ /** The file chooser to select the download folder */
+ private JFileChooser fileChooserDownloadFolder;
+ /** The download folder */
+ public static File DOWNLOADFOLDER = new File(".");
+ /** The JButton to open the file chooser dialog */
+ private final JButton button;
+
+ /**
+ * Create a settings panel
+ */
+ public SettingsRipperPanel(){
+ panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.NORTHWEST;
+
+ gbc.gridx=0;
+ gbc.gridy=0;
+ gbc.gridwidth=1;
+ gbc.insets.bottom = 10;
+ labelDownloadFolder = new JLabel("Download folder");
+ labelDownloadFolder.setFont(new Font(labelDownloadFolder.getFont().getFontName(), Font.BOLD, 15));
+ panel.add(labelDownloadFolder, gbc);
+
+ gbc.gridx=0;
+ gbc.gridy=1;
+ gbc.gridwidth=8;
+ gbc.insets.left = 20;
+ textDownloadFolder = new JTextField(DOWNLOADFOLDER.getAbsolutePath());
+ textDownloadFolder.setEditable(false);
+ textDownloadFolder.setPreferredSize(new Dimension(500, 30));
+ panel.add(textDownloadFolder,gbc);
+
+ gbc.gridx=8;
+ gbc.gridy=1;
+ gbc.gridwidth=1;
+ gbc.insets.left = 0;
+ button = new JButton("...");
+ panel.add(button,gbc);
+
+ fileChooserDownloadFolder = new JFileChooser(DOWNLOADFOLDER);
+ fileChooserDownloadFolder.setDialogTitle("Select download folder");
+ fileChooserDownloadFolder.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ fileChooserDownloadFolder.setAcceptAllFileFilterUsed(false);
+
+
+ button.addActionListener(e -> {
+ int value = fileChooserDownloadFolder.showOpenDialog(panel);
+
+ if (value == JFileChooser.APPROVE_OPTION){
+ DOWNLOADFOLDER = fileChooserDownloadFolder.getSelectedFile();
+ textDownloadFolder.setText(DOWNLOADFOLDER.getAbsolutePath());
+ }
+
+ });
+ }
+
+ /**
+ * Get the JPanel
+ * @return the JPanel
+ */
+ public JPanel getPanel() {
+ return panel;
+ }
+
+}