Added base functionality, working prototype

This commit is contained in:
2021-04-04 16:26:12 +02:00
parent 9d4317ee9d
commit 34ea601a95
19 changed files with 1987 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
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<String> listPanel;
private JTextField textField;
private final JButton button;
private final JLabel label;
private Map<String, String> elements;
public BaseRipperPanel(Map<String, String> 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<String> 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;
}
}

View File

@@ -0,0 +1,143 @@
/*
* 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<DownloadTask> listTasks;
private DefaultListModel<DownloadTask> listModel;
private JTextField textSelectedTask;
private final JLabel labelTaskCount;
private final List<DownloadTask> 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<DownloadTask> 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()));
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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);
}
});
}
}

View File

@@ -0,0 +1,124 @@
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<EpisodeWrapper> listPanel;
private DefaultListModel<EpisodeWrapper> listModel;
private JTextField textField;
private final JButton buttonDownload;
private final JLabel label;
private final List<EpisodeWrapper> episodes;
private final JButton buttonDownloadAll;
public EpisodesRipperPanel(List<EpisodeWrapper> 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;
}
}

View File

@@ -0,0 +1,132 @@
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<WebElement> shows = CrawlerUtil.getShows();
Map<String, String> 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<WebElement> seasons = CrawlerUtil.getSeasons(url);
Map<String, String> 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<EpisodeWrapper> 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;
}
}

View File

@@ -0,0 +1,90 @@
/*
* 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;
}
}