mirror of
https://github.com/mitb-archive/filebot
synced 2024-11-12 12:25:03 -05:00
* added support for downloading subtitles from Sublight
* added ZipArchive and RarArchive
This commit is contained in:
parent
094b37bcb8
commit
c49b68c836
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
interface Archive {
|
||||||
|
|
||||||
|
Map<String, ByteBuffer> extract() throws IOException;
|
||||||
|
|
||||||
|
}
|
@ -2,14 +2,46 @@
|
|||||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
public enum ArchiveType {
|
import java.io.IOException;
|
||||||
ZIP,
|
import java.nio.ByteBuffer;
|
||||||
RAR,
|
import java.util.Collections;
|
||||||
UNKNOWN;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
enum ArchiveType {
|
||||||
|
ZIP {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Archive fromData(ByteBuffer data) {
|
||||||
|
return new ZipArchive(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RAR {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Archive fromData(ByteBuffer data) {
|
||||||
|
return new RarArchive(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UNDEFINED {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Archive fromData(ByteBuffer data) {
|
||||||
|
// cannot extract data, return empty archive
|
||||||
|
return new Archive() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ByteBuffer> extract() throws IOException {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public static ArchiveType forName(String name) {
|
public static ArchiveType forName(String name) {
|
||||||
if (name == null)
|
if (name == null)
|
||||||
return UNKNOWN;
|
return UNDEFINED;
|
||||||
|
|
||||||
if (name.equalsIgnoreCase("zip"))
|
if (name.equalsIgnoreCase("zip"))
|
||||||
return ZIP;
|
return ZIP;
|
||||||
@ -17,10 +49,13 @@ public enum ArchiveType {
|
|||||||
if (name.equalsIgnoreCase("rar"))
|
if (name.equalsIgnoreCase("rar"))
|
||||||
return RAR;
|
return RAR;
|
||||||
|
|
||||||
return UNKNOWN;
|
return UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract Archive fromData(ByteBuffer data);
|
||||||
|
|
||||||
|
|
||||||
public String getExtension() {
|
public String getExtension() {
|
||||||
return toString().toLowerCase();
|
return toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.sourceforge.tuned.ByteBufferOutputStream;
|
||||||
|
|
||||||
|
import de.innosystec.unrar.exception.RarException;
|
||||||
|
import de.innosystec.unrar.rarfile.FileHeader;
|
||||||
|
|
||||||
|
|
||||||
|
class RarArchive implements Archive {
|
||||||
|
|
||||||
|
private final ByteBuffer data;
|
||||||
|
|
||||||
|
|
||||||
|
public RarArchive(ByteBuffer data) {
|
||||||
|
this.data = data.duplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, ByteBuffer> extract() throws IOException {
|
||||||
|
Map<String, ByteBuffer> vfs = new LinkedHashMap<String, ByteBuffer>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
de.innosystec.unrar.Archive rar = new de.innosystec.unrar.Archive(data.duplicate());
|
||||||
|
|
||||||
|
for (FileHeader header : rar.getFileHeaders()) {
|
||||||
|
// ignore directory entries
|
||||||
|
if (header.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBufferOutputStream buffer = new ByteBufferOutputStream(header.getDataSize());
|
||||||
|
|
||||||
|
// write contents to buffer
|
||||||
|
rar.extractFile(header, buffer);
|
||||||
|
|
||||||
|
// add memory file
|
||||||
|
vfs.put(header.getFileNameString(), buffer.getByteBuffer());
|
||||||
|
}
|
||||||
|
} catch (RarException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -56,7 +56,7 @@ public class SubtitleListCellRenderer extends AbstractFancyListCellRenderer {
|
|||||||
|
|
||||||
//TODO download + progress
|
//TODO download + progress
|
||||||
progressBar.setVisible(false);
|
progressBar.setVisible(false);
|
||||||
progressBar.setString(subtitle.getDownloadTask().getState().toString().toLowerCase());
|
progressBar.setString(subtitle.getDownload().getState().toString().toLowerCase());
|
||||||
|
|
||||||
titleLabel.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
|
titleLabel.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
|
||||||
languageLabel.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
|
languageLabel.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||||
import net.sourceforge.tuned.DownloadTask;
|
|
||||||
|
|
||||||
|
|
||||||
public class SubtitlePackage {
|
public class SubtitlePackage {
|
||||||
@ -17,14 +19,14 @@ public class SubtitlePackage {
|
|||||||
|
|
||||||
private final Language language;
|
private final Language language;
|
||||||
|
|
||||||
private final DownloadTask downloadTask;
|
private final SwingWorker<ByteBuffer, ?> download;
|
||||||
|
|
||||||
|
|
||||||
public SubtitlePackage(SubtitleDescriptor subtitleDescriptor) {
|
public SubtitlePackage(SubtitleDescriptor subtitleDescriptor) {
|
||||||
this.subtitleDescriptor = subtitleDescriptor;
|
this.subtitleDescriptor = subtitleDescriptor;
|
||||||
|
|
||||||
this.language = new Language(languageCodeByName.get(subtitleDescriptor.getLanguageName()), subtitleDescriptor.getLanguageName());
|
this.language = new Language(languageCodeByName.get(subtitleDescriptor.getLanguageName()), subtitleDescriptor.getLanguageName());
|
||||||
this.downloadTask = subtitleDescriptor.createDownloadTask();
|
this.download = subtitleDescriptor.createDownloadTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -43,8 +45,8 @@ public class SubtitlePackage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DownloadTask getDownloadTask() {
|
public SwingWorker<ByteBuffer, ?> getDownload() {
|
||||||
return downloadTask;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import net.sourceforge.tuned.ByteBufferInputStream;
|
||||||
|
import net.sourceforge.tuned.ByteBufferOutputStream;
|
||||||
|
|
||||||
|
|
||||||
|
class ZipArchive implements Archive {
|
||||||
|
|
||||||
|
private final ByteBuffer data;
|
||||||
|
|
||||||
|
|
||||||
|
public ZipArchive(ByteBuffer data) {
|
||||||
|
this.data = data.duplicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, ByteBuffer> extract() throws IOException {
|
||||||
|
Map<String, ByteBuffer> vfs = new LinkedHashMap<String, ByteBuffer>();
|
||||||
|
|
||||||
|
// read first zip entry
|
||||||
|
ZipInputStream zipInputStream = new ZipInputStream(new ByteBufferInputStream(data.duplicate()));
|
||||||
|
ZipEntry zipEntry;
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||||
|
ByteBufferOutputStream buffer = new ByteBufferOutputStream((int) zipEntry.getSize());
|
||||||
|
ReadableByteChannel fileChannel = Channels.newChannel(zipInputStream);
|
||||||
|
|
||||||
|
// write contents to buffer
|
||||||
|
while (buffer.transferFrom(fileChannel) >= 0);
|
||||||
|
|
||||||
|
// add memory file
|
||||||
|
vfs.put(zipEntry.getName(), buffer.getByteBuffer());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
zipInputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return vfs;
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,8 @@ import javax.swing.Icon;
|
|||||||
import javax.xml.ws.Holder;
|
import javax.xml.ws.Holder;
|
||||||
import javax.xml.ws.WebServiceException;
|
import javax.xml.ws.WebServiceException;
|
||||||
|
|
||||||
|
import redstone.xmlrpc.util.Base64;
|
||||||
|
|
||||||
import net.sourceforge.filebot.ResourceManager;
|
import net.sourceforge.filebot.ResourceManager;
|
||||||
import net.sourceforge.tuned.Timer;
|
import net.sourceforge.tuned.Timer;
|
||||||
import net.sublight.webservice.ArrayOfGenre;
|
import net.sublight.webservice.ArrayOfGenre;
|
||||||
@ -97,7 +99,7 @@ public class SublightSubtitleClient implements SubtitleProvider {
|
|||||||
|
|
||||||
// retrieve subtitles by name and year
|
// retrieve subtitles by name and year
|
||||||
for (Subtitle subtitle : getSubtitleList(null, movie.getName(), movie.getYear(), languageName)) {
|
for (Subtitle subtitle : getSubtitleList(null, movie.getName(), movie.getYear(), languageName)) {
|
||||||
subtitles.add(new SublightSubtitleDescriptor(subtitle));
|
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return subtitles;
|
return subtitles;
|
||||||
@ -111,7 +113,7 @@ public class SublightSubtitleClient implements SubtitleProvider {
|
|||||||
for (Subtitle subtitle : getSubtitleList(SublightVideoHasher.computeHash(videoFile), null, null, languageName)) {
|
for (Subtitle subtitle : getSubtitleList(SublightVideoHasher.computeHash(videoFile), null, null, languageName)) {
|
||||||
// only keep linked subtitles
|
// only keep linked subtitles
|
||||||
if (subtitle.isIsLinked()) {
|
if (subtitle.isIsLinked()) {
|
||||||
subtitles.add(new SublightSubtitleDescriptor(subtitle));
|
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,11 +188,34 @@ public class SublightSubtitleClient implements SubtitleProvider {
|
|||||||
if (languageName.equalsIgnoreCase("Serbian"))
|
if (languageName.equalsIgnoreCase("Serbian"))
|
||||||
return SubtitleLanguage.SERBIAN_LATIN;
|
return SubtitleLanguage.SERBIAN_LATIN;
|
||||||
|
|
||||||
// unkown language
|
// unknown language
|
||||||
throw new IllegalArgumentException("Illegal language: " + languageName);
|
throw new IllegalArgumentException("Illegal language: " + languageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected byte[] getZipArchive(Subtitle subtitle) throws WebServiceException {
|
||||||
|
// require login
|
||||||
|
login();
|
||||||
|
|
||||||
|
Holder<String> ticket = new Holder<String>();
|
||||||
|
Holder<String> data = new Holder<String>();
|
||||||
|
Holder<String> error = new Holder<String>();
|
||||||
|
|
||||||
|
webservice.getDownloadTicket(session, null, subtitle.getSubtitleID(), null, ticket, null, error);
|
||||||
|
|
||||||
|
// abort if something went wrong
|
||||||
|
checkError(error);
|
||||||
|
|
||||||
|
webservice.downloadByID3(session, subtitle.getSubtitleID(), -1, false, ticket.value, null, data, error);
|
||||||
|
|
||||||
|
// abort if something went wrong
|
||||||
|
checkError(error);
|
||||||
|
|
||||||
|
// return zip file bytes
|
||||||
|
return Base64.decode(data.value.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getSubtitleListLink(SearchResult searchResult, String languageName) {
|
public URI getSubtitleListLink(SearchResult searchResult, String languageName) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -2,17 +2,22 @@
|
|||||||
package net.sourceforge.filebot.web;
|
package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
|
|
||||||
import net.sourceforge.tuned.DownloadTask;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
import net.sublight.webservice.Subtitle;
|
import net.sublight.webservice.Subtitle;
|
||||||
|
|
||||||
|
|
||||||
public class SublightSubtitleDescriptor implements SubtitleDescriptor {
|
public class SublightSubtitleDescriptor implements SubtitleDescriptor {
|
||||||
|
|
||||||
private final Subtitle subtitle;
|
private final Subtitle subtitle;
|
||||||
|
private final SublightSubtitleClient source;
|
||||||
|
|
||||||
|
|
||||||
public SublightSubtitleDescriptor(Subtitle subtitle) {
|
public SublightSubtitleDescriptor(Subtitle subtitle, SublightSubtitleClient source) {
|
||||||
this.subtitle = subtitle;
|
this.subtitle = subtitle;
|
||||||
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -33,12 +38,6 @@ public class SublightSubtitleDescriptor implements SubtitleDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArchiveType() {
|
|
||||||
return subtitle.getSubtitleType().value().toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLanguageName() {
|
public String getLanguageName() {
|
||||||
return subtitle.getLanguage().value();
|
return subtitle.getLanguage().value();
|
||||||
@ -46,9 +45,20 @@ public class SublightSubtitleDescriptor implements SubtitleDescriptor {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DownloadTask createDownloadTask() {
|
public String getArchiveType() {
|
||||||
// TODO support
|
return "zip";
|
||||||
return new DownloadTask(null);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SwingWorker<ByteBuffer, ?> createDownloadTask() {
|
||||||
|
return new SwingWorker<ByteBuffer, Void>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuffer doInBackground() throws Exception {
|
||||||
|
return ByteBuffer.wrap(source.getZipArchive(subtitle));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
|||||||
public final class SublightVideoHasher {
|
public final class SublightVideoHasher {
|
||||||
|
|
||||||
|
|
||||||
public static String computeHash(File file) throws IOException {
|
public static String computeHash(File file) throws IOException, LinkageError {
|
||||||
byte[][] hash = new byte[4][];
|
byte[][] hash = new byte[4][];
|
||||||
|
|
||||||
// 1 byte = 0 (reserved)
|
// 1 byte = 0 (reserved)
|
||||||
@ -80,24 +80,20 @@ public final class SublightVideoHasher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static long getDuration(File file, TimeUnit unit) throws IOException {
|
protected static long getDuration(File file, TimeUnit unit) throws IOException, LinkageError {
|
||||||
try {
|
MediaInfo mediaInfo = new MediaInfo();
|
||||||
MediaInfo mediaInfo = new MediaInfo();
|
|
||||||
|
if (!mediaInfo.open(file))
|
||||||
if (!mediaInfo.open(file))
|
throw new IOException("Failed to open file: " + file);
|
||||||
throw new IllegalArgumentException("Failed to open file: " + file);
|
|
||||||
|
// get media info
|
||||||
// get media info
|
String duration = mediaInfo.get(StreamKind.General, 0, "Duration");
|
||||||
String duration = mediaInfo.get(StreamKind.General, 0, "Duration");
|
|
||||||
|
// close handle
|
||||||
// close handle
|
mediaInfo.close();
|
||||||
mediaInfo.close();
|
|
||||||
|
// convert from milliseconds to given unit
|
||||||
// convert from milliseconds to given unit
|
return unit.convert(Long.parseLong(duration), TimeUnit.MILLISECONDS);
|
||||||
return unit.convert(Long.parseLong(duration), TimeUnit.MILLISECONDS);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Failed to get video duration", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
package net.sourceforge.filebot.web;
|
package net.sourceforge.filebot.web;
|
||||||
|
|
||||||
|
|
||||||
import net.sourceforge.tuned.DownloadTask;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
|
||||||
|
|
||||||
public interface SubtitleDescriptor {
|
public interface SubtitleDescriptor {
|
||||||
@ -16,6 +18,6 @@ public interface SubtitleDescriptor {
|
|||||||
public String getArchiveType();
|
public String getArchiveType();
|
||||||
|
|
||||||
|
|
||||||
public DownloadTask createDownloadTask();
|
public SwingWorker<ByteBuffer, ?> createDownloadTask();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@ package net.sourceforge.filebot.web;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import net.sublight.webservice.Subtitle;
|
import net.sublight.webservice.Subtitle;
|
||||||
|
|
||||||
@ -82,6 +85,27 @@ public class SublightSubtitleClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getZipArchive() throws Exception {
|
||||||
|
Subtitle subtitle = new Subtitle();
|
||||||
|
subtitle.setSubtitleID("1b4e9868-dded-49d0-b6e2-2d145328f6d4");
|
||||||
|
|
||||||
|
byte[] zip = client.getZipArchive(subtitle);
|
||||||
|
|
||||||
|
// read first zip entry
|
||||||
|
ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(zip));
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipEntry entry = zipInputStream.getNextEntry();
|
||||||
|
|
||||||
|
assertEquals("Terminator The Sarah Connor Chronicles.srt", entry.getName());
|
||||||
|
assertEquals(38959, entry.getSize(), 0);
|
||||||
|
} finally {
|
||||||
|
zipInputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void logout() {
|
public static void logout() {
|
||||||
// logout manually
|
// logout manually
|
||||||
|
Loading…
Reference in New Issue
Block a user