package net.filebot.media; import static java.util.Comparator.*; import static net.filebot.MediaTypes.*; import static net.filebot.media.CachedMediaCharacteristics.*; import static net.filebot.media.MediaDetection.*; import static net.filebot.media.MediaFileUtilities.*; import static net.filebot.util.StringUtilities.*; import java.io.File; import java.util.Comparator; import java.util.regex.Pattern; public class VideoQuality implements Comparator { public static final Comparator DESCENDING_ORDER = new VideoQuality(VideoFormat.DEFAULT_GROUPS, releaseInfo.getRepackPattern()).reversed(); public static boolean isBetter(File f1, File f2) { return DESCENDING_ORDER.compare(f1, f2) < 0; } private final VideoFormat quality; private final Pattern repack; public VideoQuality(VideoFormat quality, Pattern repack) { this.quality = quality; this.repack = repack; } private final Comparator chain = comparingInt(this::getQuality) .thenComparing(VideoCodec::compare) .thenComparingInt(this::getRepack) .thenComparingDouble(this::getScore) .thenComparingLong(File::length); @Override public int compare(File f1, File f2) { return chain.compare(getPrimaryFile(f1), getPrimaryFile(f2)); } private File getPrimaryFile(File f) { return findPrimaryFile(f, VIDEO_FILES).orElse(f); } private int getRepack(File f) { return find(f.getName(), repack) ? 1 : 0; } private int getQuality(File f) { // use primary video file when checking video resolution of subtitle files or disk folders return getMediaCharacteristics(f, mi -> { Integer w = mi.getWidth(); Integer h = mi.getHeight(); // invalid media file if (w == null || h == null) { return null; } return quality.guessFormat(w, h); }).orElse(Integer.MIN_VALUE); } private double getScore(File f) { // use primary video file when checking video resolution of subtitle files or disk folders return getMediaCharacteristics(f, mi -> { Integer w = mi.getWidth(); Integer h = mi.getHeight(); Double br = mi.getBitRate(); // invalid media file if (w == null || h == null || br == null) { return null; } return w * h * br; }).orElse(Double.MIN_VALUE); } public enum VideoCodec { MPEG, AVC, HEVC; public static VideoCodec get(MediaCharacteristics mi) { switch (mi.getVideoCodec()) { case "HEVC": return HEVC; case "AVC": return AVC; case "MPEG-4 Visual": return MPEG; } // print missing codec name throw new UnsupportedOperationException("Unknown Video Codec: " + mi.getVideoCodec()); } public static int compare(File f1, File f2) { VideoCodec vc1 = getMediaCharacteristics(f1, VideoCodec::get).orElse(null); VideoCodec vc2 = getMediaCharacteristics(f2, VideoCodec::get).orElse(null); if (vc1 == null || vc2 == null) { return 0; } return vc1.compareTo(vc2); } } }