2009-04-04 15:36:12 -04:00
|
|
|
|
|
|
|
package net.sourceforge.filebot.format;
|
|
|
|
|
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
import static net.sourceforge.filebot.FileBotUtilities.SFV_FILES;
|
2009-04-04 15:36:12 -04:00
|
|
|
import static net.sourceforge.filebot.format.Define.undefined;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
2009-04-25 03:59:08 -04:00
|
|
|
import java.util.Scanner;
|
2009-05-02 19:34:04 -04:00
|
|
|
import java.util.Map.Entry;
|
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
2009-04-04 15:36:12 -04:00
|
|
|
import java.util.zip.CRC32;
|
|
|
|
|
|
|
|
import net.sf.ehcache.Cache;
|
|
|
|
import net.sf.ehcache.CacheManager;
|
|
|
|
import net.sf.ehcache.Element;
|
|
|
|
import net.sourceforge.filebot.FileBotUtilities;
|
2009-05-02 19:34:04 -04:00
|
|
|
import net.sourceforge.filebot.hash.IllegalSyntaxException;
|
|
|
|
import net.sourceforge.filebot.hash.SfvFileScanner;
|
2009-04-04 15:36:12 -04:00
|
|
|
import net.sourceforge.filebot.mediainfo.MediaInfo;
|
|
|
|
import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
|
|
|
import net.sourceforge.filebot.web.Episode;
|
2009-05-02 19:34:04 -04:00
|
|
|
import net.sourceforge.tuned.FileUtilities;
|
2009-04-04 15:36:12 -04:00
|
|
|
|
|
|
|
|
|
|
|
public class EpisodeFormatBindingBean {
|
|
|
|
|
|
|
|
private final Episode episode;
|
|
|
|
|
|
|
|
private final File mediaFile;
|
|
|
|
|
|
|
|
private MediaInfo mediaInfo;
|
|
|
|
|
|
|
|
|
|
|
|
public EpisodeFormatBindingBean(Episode episode, File mediaFile) {
|
|
|
|
this.episode = episode;
|
|
|
|
this.mediaFile = mediaFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define(undefined)
|
|
|
|
public String undefined() {
|
|
|
|
// omit expressions that depend on undefined values
|
|
|
|
throw new RuntimeException("undefined");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("n")
|
|
|
|
public String getSeriesName() {
|
|
|
|
return episode.getSeriesName();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("s")
|
|
|
|
public String getSeasonNumber() {
|
|
|
|
return episode.getSeasonNumber();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("e")
|
|
|
|
public String getEpisodeNumber() {
|
|
|
|
return episode.getEpisodeNumber();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("t")
|
|
|
|
public String getTitle() {
|
|
|
|
return episode.getTitle();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("vc")
|
|
|
|
public String getVideoCodec() {
|
|
|
|
return getMediaInfo(StreamKind.Video, 0, "Encoded_Library/Name", "CodecID/Hint", "Codec/String");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("ac")
|
|
|
|
public String getAudioCodec() {
|
|
|
|
return getMediaInfo(StreamKind.Audio, 0, "CodecID/Hint", "Codec/String");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
@Define("cf")
|
|
|
|
public String getContainerFormat() {
|
|
|
|
// container format extension
|
|
|
|
String extensions = getMediaInfo(StreamKind.General, 0, "Codec/Extensions");
|
|
|
|
|
|
|
|
// get first token
|
|
|
|
return new Scanner(extensions).next();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-04 15:36:12 -04:00
|
|
|
@Define("hi")
|
|
|
|
public String getHeightAndInterlacement() {
|
|
|
|
String height = getMediaInfo(StreamKind.Video, 0, "Height");
|
2009-04-06 16:34:33 -04:00
|
|
|
String interlacement = getMediaInfo(StreamKind.Video, 0, "Interlacement");
|
2009-04-04 15:36:12 -04:00
|
|
|
|
|
|
|
if (height == null || interlacement == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
// e.g. 720p
|
|
|
|
return height + Character.toLowerCase(interlacement.charAt(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("resolution")
|
|
|
|
public String getVideoResolution() {
|
|
|
|
String width = getMediaInfo(StreamKind.Video, 0, "Width");
|
|
|
|
String height = getMediaInfo(StreamKind.Video, 0, "Height");
|
|
|
|
|
|
|
|
if (width == null || height == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
// e.g. 1280x720
|
|
|
|
return width + 'x' + height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("crc32")
|
2009-04-26 09:34:22 -04:00
|
|
|
public String getCRC32() throws IOException, InterruptedException {
|
2009-04-04 15:36:12 -04:00
|
|
|
if (mediaFile != null) {
|
|
|
|
// try to get checksum from file name
|
2009-05-02 19:34:04 -04:00
|
|
|
String checksum = FileBotUtilities.getEmbeddedChecksum(mediaFile.getName());
|
2009-04-04 15:36:12 -04:00
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
if (checksum != null)
|
|
|
|
return checksum;
|
|
|
|
|
|
|
|
// try to get checksum from sfv file
|
|
|
|
checksum = getChecksumFromSfvFile(mediaFile);
|
|
|
|
|
|
|
|
if (checksum != null)
|
|
|
|
return checksum;
|
2009-04-04 15:36:12 -04:00
|
|
|
|
|
|
|
// calculate checksum from file
|
|
|
|
return crc32(mediaFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2009-04-06 16:34:33 -04:00
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
@Define("ext")
|
|
|
|
public String getContainerExtension() {
|
|
|
|
// file extension
|
|
|
|
return FileUtilities.getExtension(mediaFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-05 17:03:40 -04:00
|
|
|
@Define("general")
|
2009-04-06 16:34:33 -04:00
|
|
|
public Object getGeneralMediaInfo() {
|
|
|
|
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.General, 0));
|
2009-04-05 17:03:40 -04:00
|
|
|
}
|
|
|
|
|
2009-04-06 16:34:33 -04:00
|
|
|
|
2009-04-04 15:36:12 -04:00
|
|
|
@Define("video")
|
2009-04-06 16:34:33 -04:00
|
|
|
public Object getVideoInfo() {
|
|
|
|
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Video, 0));
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Define("audio")
|
2009-04-06 16:34:33 -04:00
|
|
|
public Object getAudioInfo() {
|
|
|
|
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Audio, 0));
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
|
2009-04-06 16:34:33 -04:00
|
|
|
|
2009-04-05 17:03:40 -04:00
|
|
|
@Define("text")
|
2009-04-06 16:34:33 -04:00
|
|
|
public Object getTextInfo() {
|
|
|
|
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Text, 0));
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
|
2009-04-06 16:34:33 -04:00
|
|
|
|
2009-04-05 17:03:40 -04:00
|
|
|
@Define("image")
|
2009-04-06 16:34:33 -04:00
|
|
|
public Object getImageInfo() {
|
|
|
|
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Image, 0));
|
2009-04-05 17:03:40 -04:00
|
|
|
}
|
2009-04-06 16:34:33 -04:00
|
|
|
|
2009-04-04 15:36:12 -04:00
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
@Define("episode")
|
2009-04-25 03:59:08 -04:00
|
|
|
public Episode getEpisode() {
|
|
|
|
return episode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
@Define("file")
|
2009-04-25 03:59:08 -04:00
|
|
|
public File getMediaFile() {
|
|
|
|
return mediaFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-26 09:34:22 -04:00
|
|
|
private synchronized MediaInfo getMediaInfo() {
|
2009-04-05 13:43:32 -04:00
|
|
|
if (mediaFile == null) {
|
|
|
|
throw new NullPointerException("Media file is null");
|
|
|
|
}
|
|
|
|
|
2009-04-04 15:36:12 -04:00
|
|
|
if (mediaInfo == null) {
|
2009-04-05 13:43:32 -04:00
|
|
|
mediaInfo = new MediaInfo();
|
|
|
|
|
|
|
|
if (!mediaInfo.open(mediaFile)) {
|
|
|
|
throw new RuntimeException(String.format("Cannot open file: %s", mediaFile));
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mediaInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String getMediaInfo(StreamKind streamKind, int streamNumber, String... keys) {
|
2009-04-04 16:19:03 -04:00
|
|
|
for (String key : keys) {
|
|
|
|
String value = getMediaInfo().get(streamKind, streamNumber, key);
|
|
|
|
|
|
|
|
if (value.length() > 0) {
|
|
|
|
return value;
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2009-04-26 14:57:27 -04:00
|
|
|
|
2009-05-02 19:34:04 -04:00
|
|
|
private String getChecksumFromSfvFile(File mediaFile) throws IOException {
|
|
|
|
File folder = mediaFile.getParentFile();
|
|
|
|
|
|
|
|
for (File sfvFile : folder.listFiles(SFV_FILES)) {
|
|
|
|
SfvFileScanner scanner = new SfvFileScanner(sfvFile);
|
|
|
|
|
|
|
|
try {
|
|
|
|
while (scanner.hasNext()) {
|
|
|
|
try {
|
|
|
|
Entry<File, String> entry = scanner.next();
|
|
|
|
|
|
|
|
if (mediaFile.getName().equals(entry.getKey().getPath())) {
|
|
|
|
return entry.getValue();
|
|
|
|
}
|
|
|
|
} catch (IllegalSyntaxException e) {
|
|
|
|
Logger.getLogger("global").log(Level.WARNING, e.getMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
scanner.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-26 09:34:22 -04:00
|
|
|
private String crc32(File file) throws IOException, InterruptedException {
|
2009-04-04 15:36:12 -04:00
|
|
|
// try to get checksum from cache
|
2009-04-26 14:57:27 -04:00
|
|
|
Cache cache = CacheManager.getInstance().getCache("checksum");
|
|
|
|
|
|
|
|
Element cacheEntry = cache.get(file);
|
2009-04-04 15:36:12 -04:00
|
|
|
|
|
|
|
if (cacheEntry != null) {
|
|
|
|
return (String) cacheEntry.getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate checksum
|
|
|
|
InputStream in = new FileInputStream(file);
|
|
|
|
CRC32 crc = new CRC32();
|
|
|
|
|
|
|
|
try {
|
|
|
|
byte[] buffer = new byte[32 * 1024];
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
while ((len = in.read(buffer)) >= 0) {
|
|
|
|
crc.update(buffer, 0, len);
|
2009-04-26 09:34:22 -04:00
|
|
|
|
|
|
|
// make this long-running operation interruptible
|
|
|
|
if (Thread.interrupted())
|
|
|
|
throw new InterruptedException();
|
2009-04-04 15:36:12 -04:00
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
in.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
String checksum = String.format("%08X", crc.getValue());
|
|
|
|
|
2009-04-26 14:57:27 -04:00
|
|
|
cache.put(new Element(file, checksum));
|
2009-04-04 15:36:12 -04:00
|
|
|
return checksum;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|