/* * 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 java.util.LinkedList; import java.util.List; import java.util.Locale; import com.frostwire.search.CrawlPagedWebSearchPerformer; import com.frostwire.search.SearchResult; import com.frostwire.search.domainalias.DomainAliasManager; import com.frostwire.search.extractors.YouTubeExtractor; import com.frostwire.search.extractors.YouTubeExtractor.LinkInfo; import com.frostwire.util.JsonUtils; /** * * @author gubatron * @author aldenml * */ public class YouTubeSearchPerformer extends CrawlPagedWebSearchPerformer<YouTubeSearchResult> { private static final int MAX_RESULTS = 15; public YouTubeSearchPerformer(DomainAliasManager domainAliasManager, long token, String keywords, int timeout) { super(domainAliasManager, token, keywords, timeout, 1, MAX_RESULTS); } @Override protected String getCrawlUrl(YouTubeSearchResult sr) { return null; } @Override protected List<? extends SearchResult> crawlResult(YouTubeSearchResult sr, byte[] data) throws Exception { List<YouTubeCrawledSearchResult> list = new LinkedList<YouTubeCrawledSearchResult>(); List<LinkInfo> infos = new YouTubeExtractor().extract(sr.getDetailsUrl(), sr.testConnection()); LinkInfo dashVideo = null; LinkInfo dashAudio = null; LinkInfo demuxVideo = null; for (LinkInfo inf : infos) { if (!isDash(inf)) { list.add(new YouTubeCrawledStreamableSearchResult(sr, inf, null)); } else { if (inf.fmt == 137) {// 1080p dashVideo = inf; } if (inf.fmt == 141) {// 256k dashAudio = inf; } if (inf.fmt == 140 && dashAudio == null) {// 128k dashAudio = inf; } if (inf.fmt == 22 || inf.fmt == 84) { demuxVideo = inf; } } } if (dashVideo != null && dashAudio != null) { list.add(new YouTubeCrawledSearchResult(sr, dashVideo, dashAudio)); } if (dashAudio != null) { list.add(new YouTubeCrawledStreamableSearchResult(sr, null, dashAudio)); } else { if (demuxVideo != null) { list.add(new YouTubeCrawledStreamableSearchResult(sr, null, demuxVideo)); } } return list; } @Override protected String getUrl(int page, String encodedKeywords) { return String.format(Locale.US, "https://gdata.youtube.com/feeds/api/videos?q=%s&orderby=relevance&start-index=1&max-results=%d&alt=json&prettyprint=true&v=2", encodedKeywords, MAX_RESULTS); } @Override protected List<? extends SearchResult> searchPage(String page) { List<SearchResult> result = new LinkedList<SearchResult>(); String json = fixJson(page); YouTubeResponse response = JsonUtils.toObject(json, YouTubeResponse.class); boolean testConnection = true; for (YouTubeEntry entry : response.feed.entry) { if (!isStopped()) { YouTubeSearchResult sr = new YouTubeSearchResult(entry, testConnection); result.add(sr); if (testConnection) { testConnection = false; } } } return result; } private String fixJson(String json) { return json.replace("\"$t\"", "\"title\""). replace("\"yt$userId\"", "\"ytuserId\""). replace("\"media$group\"", "\"mediagroup\""). replace("\"media$content\"", "\"mediacontent\""); } private boolean isDash(LinkInfo info) { switch (info.fmt) { case 133: case 134: case 135: case 136: case 137: case 139: case 140: case 141: return true; default: return false; } } }