* Extract API changes to include FileSize

This commit is contained in:
Reinhard Pointner 2014-01-22 07:52:25 +00:00
parent dea0a1fb83
commit 66a6278611
5 changed files with 109 additions and 136 deletions

View File

@ -1,7 +1,5 @@
package net.sourceforge.filebot.archive; package net.sourceforge.filebot.archive;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
@ -23,21 +21,21 @@ import net.sf.sevenzipjbinding.ISevenZipInArchive;
import net.sf.sevenzipjbinding.PropID; import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.SevenZipException;
import net.sourceforge.filebot.MediaTypes; import net.sourceforge.filebot.MediaTypes;
import net.sourceforge.filebot.vfs.FileInfo;
import net.sourceforge.filebot.vfs.SimpleFileInfo;
import net.sourceforge.tuned.FileUtilities.ExtensionFileFilter; import net.sourceforge.tuned.FileUtilities.ExtensionFileFilter;
public class Archive implements Closeable { public class Archive implements Closeable {
private ISevenZipInArchive inArchive; private ISevenZipInArchive inArchive;
private ArchiveOpenVolumeCallback openVolume; private ArchiveOpenVolumeCallback openVolume;
public Archive(File file) throws Exception { public Archive(File file) throws Exception {
// initialize 7-Zip-JBinding // initialize 7-Zip-JBinding
if (!file.exists()) { if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath()); throw new FileNotFoundException(file.getAbsolutePath());
} }
try { try {
openVolume = new ArchiveOpenVolumeCallback(); openVolume = new ArchiveOpenVolumeCallback();
if (!hasMultiPartIndex(file)) { if (!hasMultiPartIndex(file)) {
@ -51,52 +49,48 @@ public class Archive implements Closeable {
throw (Exception) e.getTargetException(); throw (Exception) e.getTargetException();
} }
} }
public int itemCount() throws SevenZipException { public int itemCount() throws SevenZipException {
return inArchive.getNumberOfItems(); return inArchive.getNumberOfItems();
} }
public Map<PropID, Object> getItem(int index) throws SevenZipException { public Map<PropID, Object> getItem(int index) throws SevenZipException {
Map<PropID, Object> item = new EnumMap<PropID, Object>(PropID.class); Map<PropID, Object> item = new EnumMap<PropID, Object>(PropID.class);
for (PropID prop : PropID.values()) { for (PropID prop : PropID.values()) {
Object value = inArchive.getProperty(index, prop); Object value = inArchive.getProperty(index, prop);
if (value != null) { if (value != null) {
item.put(prop, value); item.put(prop, value);
} }
} }
return item; return item;
} }
public List<FileInfo> listFiles() throws SevenZipException {
public List<File> listFiles() throws SevenZipException { List<FileInfo> paths = new ArrayList<FileInfo>();
List<File> paths = new ArrayList<File>();
for (int i = 0; i < inArchive.getNumberOfItems(); i++) { for (int i = 0; i < inArchive.getNumberOfItems(); i++) {
boolean isFolder = (Boolean) inArchive.getProperty(i, PropID.IS_FOLDER); boolean isFolder = (Boolean) inArchive.getProperty(i, PropID.IS_FOLDER);
if (!isFolder) { if (!isFolder) {
String path = (String) inArchive.getProperty(i, PropID.PATH); String path = (String) inArchive.getProperty(i, PropID.PATH);
Long length = (Long) inArchive.getProperty(i, PropID.SIZE);
if (path != null) { if (path != null) {
paths.add(new File(path)); paths.add(new SimpleFileInfo(path, length != null ? length : -1));
} }
} }
} }
return paths; return paths;
} }
public void extract(ExtractOutProvider outputMapper) throws SevenZipException { public void extract(ExtractOutProvider outputMapper) throws SevenZipException {
inArchive.extract(null, false, new ExtractCallback(inArchive, outputMapper)); inArchive.extract(null, false, new ExtractCallback(inArchive, outputMapper));
} }
public void extract(ExtractOutProvider outputMapper, FileFilter filter) throws SevenZipException { public void extract(ExtractOutProvider outputMapper, FileFilter filter) throws SevenZipException {
List<Integer> selection = new ArrayList<Integer>(); List<Integer> selection = new ArrayList<Integer>();
for (int i = 0; i < inArchive.getNumberOfItems(); i++) { for (int i = 0; i < inArchive.getNumberOfItems(); i++) {
boolean isFolder = (Boolean) inArchive.getProperty(i, PropID.IS_FOLDER); boolean isFolder = (Boolean) inArchive.getProperty(i, PropID.IS_FOLDER);
if (!isFolder) { if (!isFolder) {
@ -106,15 +100,14 @@ public class Archive implements Closeable {
} }
} }
} }
int[] indices = new int[selection.size()]; int[] indices = new int[selection.size()];
for (int i = 0; i < indices.length; i++) { for (int i = 0; i < indices.length; i++) {
indices[i] = selection.get(i); indices[i] = selection.get(i);
} }
inArchive.extract(indices, false, new ExtractCallback(inArchive, outputMapper)); inArchive.extract(indices, false, new ExtractCallback(inArchive, outputMapper));
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
try { try {
@ -125,41 +118,38 @@ public class Archive implements Closeable {
openVolume.close(); openVolume.close();
} }
} }
public static Set<String> getArchiveTypes() { public static Set<String> getArchiveTypes() {
Set<String> extensions = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); Set<String> extensions = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
// application data // application data
extensions.addAll(MediaTypes.getDefault().getExtensionList("archive")); extensions.addAll(MediaTypes.getDefault().getExtensionList("archive"));
// formats provided by the library // formats provided by the library
for (ArchiveFormat it : ArchiveFormat.values()) { for (ArchiveFormat it : ArchiveFormat.values()) {
extensions.add(it.getMethodName()); extensions.add(it.getMethodName());
} }
return extensions; return extensions;
} }
private static final Pattern multiPartIndex = Pattern.compile("[.][0-9]{3}+$"); private static final Pattern multiPartIndex = Pattern.compile("[.][0-9]{3}+$");
public static boolean hasMultiPartIndex(File file) { public static boolean hasMultiPartIndex(File file) {
return multiPartIndex.matcher(file.getName()).find(); return multiPartIndex.matcher(file.getName()).find();
} }
public static final FileFilter VOLUME_ONE_FILTER = new FileFilter() { public static final FileFilter VOLUME_ONE_FILTER = new FileFilter() {
private Pattern volume = Pattern.compile("[.]r[0-9]+$|[.]part[0-9]+|[.][0-9]+$", Pattern.CASE_INSENSITIVE); private Pattern volume = Pattern.compile("[.]r[0-9]+$|[.]part[0-9]+|[.][0-9]+$", Pattern.CASE_INSENSITIVE);
private FileFilter archives = new ExtensionFileFilter(getArchiveTypes()); private FileFilter archives = new ExtensionFileFilter(getArchiveTypes());
@Override @Override
public boolean accept(File path) { public boolean accept(File path) {
if (!archives.accept(path) && !hasMultiPartIndex(path)) { if (!archives.accept(path) && !hasMultiPartIndex(path)) {
return false; return false;
} }
Matcher matcher = volume.matcher(path.getName()); Matcher matcher = volume.matcher(path.getName());
if (matcher.find()) { if (matcher.find()) {
Scanner scanner = new Scanner(matcher.group()).useDelimiter("\\D+"); Scanner scanner = new Scanner(matcher.group()).useDelimiter("\\D+");
@ -167,10 +157,10 @@ public class Archive implements Closeable {
return false; return false;
} }
} }
return true; return true;
} }
}; };
} }

View File

@ -58,6 +58,7 @@ import net.sourceforge.filebot.similarity.SimilarityComparator;
import net.sourceforge.filebot.similarity.SimilarityMetric; import net.sourceforge.filebot.similarity.SimilarityMetric;
import net.sourceforge.filebot.subtitle.SubtitleFormat; import net.sourceforge.filebot.subtitle.SubtitleFormat;
import net.sourceforge.filebot.subtitle.SubtitleNaming; import net.sourceforge.filebot.subtitle.SubtitleNaming;
import net.sourceforge.filebot.vfs.FileInfo;
import net.sourceforge.filebot.vfs.MemoryFile; import net.sourceforge.filebot.vfs.MemoryFile;
import net.sourceforge.filebot.web.AudioTrack; import net.sourceforge.filebot.web.AudioTrack;
import net.sourceforge.filebot.web.Episode; import net.sourceforge.filebot.web.Episode;
@ -1085,8 +1086,8 @@ public class CmdlineOperations implements CmdlineInterface {
final FileMapper outputMapper = new FileMapper(outputFolder, false); final FileMapper outputMapper = new FileMapper(outputFolder, false);
final List<File> outputMapping = new ArrayList<File>(); final List<File> outputMapping = new ArrayList<File>();
for (File entry : archive.listFiles()) { for (FileInfo entry : archive.listFiles()) {
outputMapping.add(outputMapper.getOutputFile(entry)); outputMapping.add(outputMapper.getOutputFile(new File(entry.getPath())));
} }
final Set<File> selection = new TreeSet<File>(); final Set<File> selection = new TreeSet<File>();

View File

@ -1,20 +1,16 @@
package net.sourceforge.filebot.cli; package net.sourceforge.filebot.cli;
public enum ConflictAction { public enum ConflictAction {
OVERRIDE, SKIP, OVERRIDE, FAIL, AUTO;
SKIP,
FAIL;
public static ConflictAction forName(String action) { public static ConflictAction forName(String action) {
for (ConflictAction it : values()) { for (ConflictAction it : values()) {
if (it.name().equalsIgnoreCase(action)) if (it.name().equalsIgnoreCase(action))
return it; return it;
} }
throw new IllegalArgumentException("Illegal conflict action: " + action); throw new IllegalArgumentException("Illegal conflict action: " + action);
} }
} }

View File

@ -53,6 +53,7 @@ import net.sourceforge.filebot.similarity.SequenceMatchSimilarity;
import net.sourceforge.filebot.similarity.SeriesNameMatcher; import net.sourceforge.filebot.similarity.SeriesNameMatcher;
import net.sourceforge.filebot.similarity.SimilarityComparator; import net.sourceforge.filebot.similarity.SimilarityComparator;
import net.sourceforge.filebot.similarity.SimilarityMetric; import net.sourceforge.filebot.similarity.SimilarityMetric;
import net.sourceforge.filebot.vfs.FileInfo;
import net.sourceforge.filebot.web.Date; import net.sourceforge.filebot.web.Date;
import net.sourceforge.filebot.web.Episode; import net.sourceforge.filebot.web.Episode;
import net.sourceforge.filebot.web.Movie; import net.sourceforge.filebot.web.Movie;
@ -95,8 +96,8 @@ public class MediaDetection {
FileFilter diskFolderEntryFilter = releaseInfo.getDiskFolderEntryFilter(); FileFilter diskFolderEntryFilter = releaseInfo.getDiskFolderEntryFilter();
Archive iso = new Archive(file); Archive iso = new Archive(file);
try { try {
for (File path : iso.listFiles()) { for (FileInfo it : iso.listFiles()) {
for (File entry : listPath(path)) { for (File entry : listPath(new File(it.getPath()))) {
if (diskFolderEntryFilter.accept(entry)) { if (diskFolderEntryFilter.accept(entry)) {
return true; return true;
} }

View File

@ -1,7 +1,5 @@
package net.sourceforge.filebot.ui.analyze; package net.sourceforge.filebot.ui.analyze;
import static net.sourceforge.filebot.ui.NotificationLogging.*; import static net.sourceforge.filebot.ui.NotificationLogging.*;
import static net.sourceforge.tuned.ExceptionUtilities.*; import static net.sourceforge.tuned.ExceptionUtilities.*;
import static net.sourceforge.tuned.FileUtilities.*; import static net.sourceforge.tuned.FileUtilities.*;
@ -38,6 +36,8 @@ import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.filebot.archive.Archive; import net.sourceforge.filebot.archive.Archive;
import net.sourceforge.filebot.archive.FileMapper; import net.sourceforge.filebot.archive.FileMapper;
import net.sourceforge.filebot.ui.analyze.FileTree.FolderNode; import net.sourceforge.filebot.ui.analyze.FileTree.FolderNode;
import net.sourceforge.filebot.vfs.FileInfo;
import net.sourceforge.tuned.FileUtilities;
import net.sourceforge.tuned.ui.GradientStyle; import net.sourceforge.tuned.ui.GradientStyle;
import net.sourceforge.tuned.ui.LoadingOverlayPane; import net.sourceforge.tuned.ui.LoadingOverlayPane;
import net.sourceforge.tuned.ui.ProgressDialog; import net.sourceforge.tuned.ui.ProgressDialog;
@ -45,57 +45,53 @@ import net.sourceforge.tuned.ui.ProgressDialog.Cancellable;
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
import net.sourceforge.tuned.ui.notification.SeparatorBorder; import net.sourceforge.tuned.ui.notification.SeparatorBorder;
class ExtractTool extends Tool<TableModel> { class ExtractTool extends Tool<TableModel> {
private JTable table = new JTable(new ArchiveEntryModel()); private JTable table = new JTable(new ArchiveEntryModel());
public ExtractTool() { public ExtractTool() {
super("Archives"); super("Archives");
table.setFillsViewportHeight(true); table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true); table.setAutoCreateRowSorter(true);
table.setAutoCreateColumnsFromModel(true); table.setAutoCreateColumnsFromModel(true);
table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setRowHeight(20); table.setRowHeight(20);
JScrollPane tableScrollPane = new JScrollPane(table); JScrollPane tableScrollPane = new JScrollPane(table);
tableScrollPane.setBorder(new SeparatorBorder(2, new Color(0, 0, 0, 90), GradientStyle.TOP_TO_BOTTOM, SeparatorBorder.Position.BOTTOM)); tableScrollPane.setBorder(new SeparatorBorder(2, new Color(0, 0, 0, 90), GradientStyle.TOP_TO_BOTTOM, SeparatorBorder.Position.BOTTOM));
setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]")); setLayout(new MigLayout("insets 0, nogrid, fill", "align center", "[fill][pref!]"));
add(new LoadingOverlayPane(tableScrollPane, this, "20px", "30px"), "grow, wrap"); add(new LoadingOverlayPane(tableScrollPane, this, "20px", "30px"), "grow, wrap");
add(new JButton(extractAction), "gap top rel, gap bottom unrel"); add(new JButton(extractAction), "gap top rel, gap bottom unrel");
} }
@Override @Override
protected void setModel(TableModel model) { protected void setModel(TableModel model) {
table.setModel(model); table.setModel(model);
} }
@Override @Override
protected TableModel createModelInBackground(FolderNode sourceModel) throws InterruptedException { protected TableModel createModelInBackground(FolderNode sourceModel) throws InterruptedException {
List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>(); List<ArchiveEntry> entries = new ArrayList<ArchiveEntry>();
try { try {
for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) { for (Iterator<File> iterator = sourceModel.fileIterator(); iterator.hasNext();) {
File file = iterator.next(); File file = iterator.next();
// ignore non-archives files and trailing multi-volume parts // ignore non-archives files and trailing multi-volume parts
if (Archive.VOLUME_ONE_FILTER.accept(file)) { if (Archive.VOLUME_ONE_FILTER.accept(file)) {
Archive archive = new Archive(file); Archive archive = new Archive(file);
try { try {
for (File it : archive.listFiles()) { for (FileInfo it : archive.listFiles()) {
entries.add(new ArchiveEntry(file, it)); entries.add(new ArchiveEntry(file, it));
} }
} finally { } finally {
archive.close(); archive.close();
} }
} }
// unwind thread, if we have been cancelled // unwind thread, if we have been cancelled
if (Thread.interrupted()) { if (Thread.interrupted()) {
throw new InterruptedException(); throw new InterruptedException();
@ -108,20 +104,19 @@ class ExtractTool extends Tool<TableModel> {
} }
UILogger.log(Level.WARNING, e.getMessage(), e); UILogger.log(Level.WARNING, e.getMessage(), e);
} }
return new ArchiveEntryModel(entries); return new ArchiveEntryModel(entries);
} }
private Action extractAction = new AbstractAction("Extract All", ResourceManager.getIcon("package.extract")) { private Action extractAction = new AbstractAction("Extract All", ResourceManager.getIcon("package.extract")) {
@Override @Override
public void actionPerformed(ActionEvent evt) { public void actionPerformed(ActionEvent evt) {
final List<File> archives = ((ArchiveEntryModel) table.getModel()).getArchiveList(); final List<File> archives = ((ArchiveEntryModel) table.getModel()).getArchiveList();
if (archives.isEmpty()) { if (archives.isEmpty()) {
return; return;
} }
Window window = getWindow(evt.getSource()); Window window = getWindow(evt.getSource());
JFileChooser chooser = new JFileChooser(archives.get(0).getParentFile()); JFileChooser chooser = new JFileChooser(archives.get(0).getParentFile());
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
@ -129,18 +124,18 @@ class ExtractTool extends Tool<TableModel> {
if (chooser.showSaveDialog(window) != JFileChooser.APPROVE_OPTION) { if (chooser.showSaveDialog(window) != JFileChooser.APPROVE_OPTION) {
return; return;
} }
final ExtractJob job = new ExtractJob(archives, chooser.getSelectedFile()); final ExtractJob job = new ExtractJob(archives, chooser.getSelectedFile());
final ProgressDialog dialog = new ProgressDialog(window, job); final ProgressDialog dialog = new ProgressDialog(window, job);
dialog.setLocation(getOffsetLocation(dialog.getOwner())); dialog.setLocation(getOffsetLocation(dialog.getOwner()));
dialog.setTitle("Extracting files..."); dialog.setTitle("Extracting files...");
dialog.setIcon((Icon) getValue(SMALL_ICON)); dialog.setIcon((Icon) getValue(SMALL_ICON));
dialog.setIndeterminate(true); dialog.setIndeterminate(true);
// close progress dialog when worker is finished // close progress dialog when worker is finished
job.addPropertyChangeListener(new SwingWorkerPropertyChangeAdapter() { job.addPropertyChangeListener(new SwingWorkerPropertyChangeAdapter() {
@Override @Override
protected void event(String name, Object oldValue, Object newValue) { protected void event(String name, Object oldValue, Object newValue) {
if (name.equals("currentFile")) { if (name.equals("currentFile")) {
@ -149,48 +144,41 @@ class ExtractTool extends Tool<TableModel> {
dialog.setWindowTitle(note); dialog.setWindowTitle(note);
} }
} }
@Override @Override
protected void done(PropertyChangeEvent evt) { protected void done(PropertyChangeEvent evt) {
dialog.close(); dialog.close();
} }
}); });
job.execute(); job.execute();
dialog.setVisible(true); dialog.setVisible(true);
} }
}; };
private static class ArchiveEntry { private static class ArchiveEntry {
public final File archive; public final File archive;
public final File entry; public final FileInfo entry;
public ArchiveEntry(File archive, FileInfo entry) {
public ArchiveEntry(File archive, File entry) {
this.archive = archive; this.archive = archive;
this.entry = entry; this.entry = entry;
} }
} }
private static class ArchiveEntryModel extends AbstractTableModel { private static class ArchiveEntryModel extends AbstractTableModel {
private final ArchiveEntry[] data; private final ArchiveEntry[] data;
public ArchiveEntryModel() { public ArchiveEntryModel() {
this.data = new ArchiveEntry[0]; this.data = new ArchiveEntry[0];
} }
public ArchiveEntryModel(Collection<ArchiveEntry> data) { public ArchiveEntryModel(Collection<ArchiveEntry> data) {
this.data = data.toArray(new ArchiveEntry[data.size()]); this.data = data.toArray(new ArchiveEntry[data.size()]);
} }
public List<File> getArchiveList() { public List<File> getArchiveList() {
Set<File> archives = new LinkedHashSet<File>(); Set<File> archives = new LinkedHashSet<File>();
for (ArchiveEntry it : data) { for (ArchiveEntry it : data) {
@ -198,68 +186,66 @@ class ExtractTool extends Tool<TableModel> {
} }
return new ArrayList<File>(archives); return new ArrayList<File>(archives);
} }
@Override @Override
public int getRowCount() { public int getRowCount() {
return data.length; return data.length;
} }
@Override @Override
public int getColumnCount() { public int getColumnCount() {
return 2; return 3;
} }
@Override @Override
public String getColumnName(int column) { public String getColumnName(int column) {
switch (column) { switch (column) {
case 0: case 0:
return "File"; return "File";
case 1: case 1:
return "Path"; return "Path";
case 2:
return "Size";
} }
return null; return null;
} }
@Override @Override
public Object getValueAt(int row, int column) { public Object getValueAt(int row, int column) {
switch (column) { switch (column) {
case 0: case 0:
return data[row].entry.getName(); return data[row].entry.getName();
case 1: case 1:
File root = new File(data[row].archive.getName()); File root = new File(data[row].archive.getName());
File prefix = data[row].entry.getParentFile(); File prefix = new File(data[row].entry.getPath()).getParentFile();
File path = (prefix == null) ? root : new File(root, prefix.getPath()); File path = (prefix == null) ? root : new File(root, prefix.getPath());
return normalizePathSeparators(path.getPath()); return normalizePathSeparators(path.getPath());
case 2:
return FileUtilities.formatSize(data[row].entry.getLength());
} }
return null; return null;
} }
} }
protected static class ExtractJob extends SwingWorker<Void, Void> implements Cancellable { protected static class ExtractJob extends SwingWorker<Void, Void> implements Cancellable {
private final File[] archives; private final File[] archives;
private final File outputRoot; private final File outputRoot;
public ExtractJob(Collection<File> archives, File outputRoot) { public ExtractJob(Collection<File> archives, File outputRoot) {
this.archives = archives.toArray(new File[archives.size()]); this.archives = archives.toArray(new File[archives.size()]);
this.outputRoot = outputRoot; this.outputRoot = outputRoot;
} }
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
for (File it : archives) { for (File it : archives) {
try { try {
// update progress dialog // update progress dialog
firePropertyChange("currentFile", null, it); firePropertyChange("currentFile", null, it);
Archive archive = new Archive(it); Archive archive = new Archive(it);
try { try {
File outputFolder = (outputRoot != null) ? outputRoot : new File(it.getParentFile(), getNameWithoutExtension(it.getName())); File outputFolder = (outputRoot != null) ? outputRoot : new File(it.getParentFile(), getNameWithoutExtension(it.getName()));
@ -271,20 +257,19 @@ class ExtractTool extends Tool<TableModel> {
} catch (Exception e) { } catch (Exception e) {
UILogger.log(Level.WARNING, "Failed to extract archive: " + it.getName(), e); UILogger.log(Level.WARNING, "Failed to extract archive: " + it.getName(), e);
} }
if (isCancelled()) { if (isCancelled()) {
throw new CancellationException(); throw new CancellationException();
} }
} }
return null; return null;
} }
@Override @Override
public boolean cancel() { public boolean cancel() {
return cancel(true); return cancel(true);
} }
} }
} }