/*
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
* Copyright (c) 2011-2014, FrostWire(R). All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.frostwire.search.youtube;
import org.apache.commons.io.FilenameUtils;
import com.frostwire.search.AbstractCrawledSearchResult;
import com.frostwire.search.HttpSearchResult;
import com.frostwire.search.extractors.YouTubeExtractor.LinkInfo;
/**
* @author gubatron
* @author aldenml
*
*/
public class YouTubeCrawledSearchResult extends AbstractCrawledSearchResult implements HttpSearchResult {
private final LinkInfo video;
private final LinkInfo audio;
private final String filename;
private final String displayName;
private final long size;
private final String downloadUrl;
public YouTubeCrawledSearchResult(YouTubeSearchResult sr, LinkInfo video, LinkInfo audio) {
super(sr);
this.video = video;
this.audio = audio;
this.filename = buildFilename(video, audio);
this.displayName = FilenameUtils.getBaseName(this.filename);
this.size = buildSize((int) sr.getSize(), video, audio);
this.downloadUrl = buildDownloadUrl(video, audio);
}
public LinkInfo getVideo() {
return video;
}
public LinkInfo getAudio() {
return audio;
}
@Override
public String getFilename() {
return filename;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public long getSize() {
return size;
}
@Override
public String getDownloadUrl() {
return downloadUrl;
}
private String buildFilename(LinkInfo video, LinkInfo audio) {
String filename;
if (video != null && audio == null) {
filename = String.format("%s_%s_%s_%s.%s", video.filename, video.format.video, video.format.audio, video.format.quality, video.format.ext);
} else if (video == null && audio != null) {
String ext = audio.format.ext.equals("mp4") ? "m4a" : audio.format.ext;
filename = String.format("%s_%s_%s_%s.%s", audio.filename, audio.format.video, audio.format.audio, audio.format.quality, ext);
} else if (video != null && audio != null) {
filename = String.format("%s_%s_%s_%s.%s", video.filename, video.format.video, audio.format.audio, video.format.quality, "mp4");
} else {
throw new IllegalArgumentException("No track defined");
}
return filename;
}
/**
* Upper guess to determine the duration in bytes, using highest bitrate of the stream.
* @param durationInSeconds
* @param linfo
* @return (([(video bitrate)] + [(audio bitrate)])*durationInSeconds)/8
*/
private long buildSize(int durationInSeconds, LinkInfo linfo) {
long result = -1;
double bitRateSum = 0;
switch (linfo.fmt) {
case 5:// new Format("flv", "H263", "MP3", "240p"));
bitRateSum = 0.25 + 64d/1024d;
break;
case 6://, new Format("flv", "H263", "MP3", "270p"));
bitRateSum = 0.8 + 64d/1024d;
break;
case 17://, new Format("3gp", "H264", "AAC", "144p"));
bitRateSum = 0.05 + 24d/1024d;
break;
case 18://, new Format("mp4", "H264", "AAC", "360p"));
bitRateSum = 0.5 + 96d/1024d;
break;
case 22://, new Format("mp4", "H264", "AAC", "720p"));
bitRateSum = 2.9 + 192d/1024d;
break;
case 34://, new Format("flv", "H264", "AAC", "360p"));
bitRateSum = 0.5 + 128d/1024d;
break;
case 35://, new Format("flv", "H264", "AAC", "480p"));
bitRateSum = 1 + 128d/1024d;
break;
case 36://, new Format("3gp", "H264", "AAC", "240p"));
bitRateSum = 0.17 + 38d/1024d;
break;
case 37://, new Format("mp4", "H264", "AAC", "1080p"));
bitRateSum = 5.9 + 192d/1024d;
break;
case 38://, new Format("mp4", "H264", "AAC", "3072p"));
bitRateSum = 5 + 192d/1024d;
break;
case 43://, new Format("webm", "VP8", "Vorbis", "360p"));
bitRateSum = 0.5 + 128d/1024d;
break;
case 44://, new Format("webm", "VP8", "Vorbis", "480p"));
bitRateSum = 1 + 128d/1024d;
break;
case 45://, new Format("webm", "VP8", "Vorbis", "720p"));
bitRateSum = 2 + 192d/1024d;
break;
case 46://, new Format("webm", "VP8", "Vorbis", "1080p"));
bitRateSum = 3 + 192d/1024d;
break;
case 82://, new Format("mp4", "H264", "AAC", "360p"));
bitRateSum = 0.5 + 96d/1024d;
break;
case 83://, new Format("mp4", "H264", "AAC", "240p"));
bitRateSum = 0.5 + 96d/1024d;
break;
case 84://, new Format("mp4", "H264", "AAC", "720p"));
bitRateSum = 2.9 + 152d/1024d;
break;
case 85://, new Format("mp4", "H264", "AAC", "520p"));
bitRateSum = 2.9 + 152d/1024d;
break;
case 100://, new Format("webm", "VP8", "Vorbis", "360p"));
bitRateSum = 0.5 + 128d/1024d;
break;
case 101://, new Format("webm", "VP8", "Vorbis", "360p"));
bitRateSum = 1 + 192d/1024d;
break;
case 102://, new Format("webm", "VP8", "Vorbis", "720p"));
bitRateSum = 2 + 192d/1024d;
break;
// dash video
case 133://, new Format("m4v", "H264", "", "240p"));
bitRateSum = 0.3 + 256d/1024d;
break;
case 134://, new Format("m4v", "H264", "", "360p"));
bitRateSum = 0.4 + 256d/1024d;
break;
case 135://, new Format("m4v", "H264", "", "480p"));
bitRateSum = 1 + 256d/1024d;
break;
case 136://, new Format("m4v", "H264", "", "720p"));
bitRateSum = 1.5 + 256d/1024d;
break;
case 137://, new Format("m4v", "H264", "", "1080p"));
bitRateSum = 2.9 + 256d/1024d;
break;
// dash audio
case 139://, new Format("m4a", "", "AAC", "48k"));
bitRateSum = 48d/1024d;
break;
case 140://, new Format("m4a", "", "AAC", "128k"));
bitRateSum = 128d/1024d;
break;
case 141://, new Format("m4a", "", "AAC", "256k"));
bitRateSum = 256d/1024d;
break;
}
bitRateSum = bitRateSum * 1024 * 1024; //Mbits to bits.
result = (long) (Math.ceil((bitRateSum * durationInSeconds)/8));
return result;
}
private long buildSize(int durationInSeconds, LinkInfo video, LinkInfo audio) {
long size = UNKNOWN_SIZE;
if (durationInSeconds != UNKNOWN_SIZE) {
if (video != null && audio == null) {
size = buildSize(durationInSeconds,video);
} else if (video == null && audio != null) {
size = buildSize(durationInSeconds, audio);
} else if (video != null && audio != null) {
size = buildSize(durationInSeconds,video);
} else {
throw new IllegalArgumentException("No track defined");
}
}
return size;
}
private String buildDownloadUrl(LinkInfo video, LinkInfo audio) {
String downloadUrl;
if (video != null && audio == null) {
downloadUrl = video.link;
} else if (video == null && audio != null) {
downloadUrl = audio.link;
} else if (video != null && audio != null) {
downloadUrl = null;
} else {
throw new IllegalArgumentException("No track defined");
}
return downloadUrl;
}
}