public static final HashSet<String> handleBase64Decode(final String b64) { if (b64 == null) { return null; } final HashSet<String> results = new HashSet<String>(); String finallink = b64; int i = 0; // this covers nested encoding. while (i < 20 && finallink != null && !new Regex(finallink, "(?:ftp|https?)://.+").matches()) { i++; // cleanup crap after padding. this can break subsequent tries finallink = Encoding.Base64Decode(finallink.replaceFirst("(={1,2})[\\w\\+]+$", "$1")); // urldecode if (finallink != null && new Regex(finallink, "%[0-9A-Fa-f]{2}").matches()) { finallink = Encoding.urlDecode(finallink, false); } // whitespace cleanup finallink = StringUtils.trim(finallink); } // determine multi or single result? final String[] multi = new Regex(finallink, "(?:https?|ftp)://").getColumn(-1); if (multi != null && multi.length > 1) { // because links might not be separated or deliminated, its best to use htmlparser final String[] links = HTMLParser.getHttpLinks(finallink, ""); if (links != null) { for (final String link : links) { results.add(link); } } } else { results.add(finallink); } return results; }
private HashMap<Integer, String[]> parseLinks(String html5_fmt_map, boolean allowVideoOnly) { final HashMap<Integer, String[]> links = new HashMap<Integer, String[]>(); if (html5_fmt_map != null) { if (html5_fmt_map.contains(UNSUPPORTEDRTMP)) { return links; } String[] html5_hits = new Regex(html5_fmt_map, "(.*?)(,|$)").getColumn(0); if (html5_hits != null) { for (String hit : html5_hits) { hit = unescape(hit); String hitUrl = new Regex(hit, "url=(http.*?)(\\&|$)").getMatch(0); String sig = new Regex(hit, "url=http.*?(\\&|$)(sig|signature)=(.*?)(\\&|$)").getMatch(2); if (sig == null) sig = new Regex(hit, "(sig|signature)=(.*?)(\\&|$)").getMatch(1); if (sig == null) sig = new Regex(hit, "(sig|signature)%3D(.*?)%26").getMatch(1); if (sig == null) sig = decryptSignature(new Regex(hit, "s=(.*?)(\\&|$)").getMatch(0)); String hitFmt = new Regex(hit, "itag=(\\d+)").getMatch(0); String hitQ = new Regex(hit, "quality=(.*?)(\\&|$)").getMatch(0); if (hitQ == null && allowVideoOnly) hitQ = "unknown"; if (hitUrl != null && hitFmt != null && hitQ != null) { hitUrl = unescape(hitUrl.replaceAll("\\\\/", "/")); if (hitUrl.startsWith("http%253A")) { hitUrl = Encoding.htmlDecode(hitUrl); } String[] inst = null; if (hitUrl.contains("sig")) { inst = new String[] {Encoding.htmlDecode(Encoding.urlDecode(hitUrl, true)), hitQ}; } else { inst = new String[] { Encoding.htmlDecode(Encoding.urlDecode(hitUrl, true) + "&signature=" + sig), hitQ }; } links.put(Integer.parseInt(hitFmt), inst); } } } } return links; }
@Override public void handleFree(DownloadLink downloadLink) throws Exception { requestFileInformation(downloadLink); br.postPage(br.getURL(), "gotovideo=1"); dllink = br.getRegex("file','(http[^']+sharesix\\.net/streams/[^']+)").getMatch(0); if (dllink == null) throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); dllink = Encoding.urlDecode(dllink, false); dl = jd.plugins.BrowserAdapter.openDownload(br, downloadLink, dllink, true, 0); if (!dl.getConnection().isContentDisposition()) { br.followConnection(); throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); } dl.startDownload(); }
@Override public AvailableStatus requestFileInformation(DownloadLink downloadLink) throws IOException, PluginException { this.setBrowserExclusive(); br.setFollowRedirects(true); br.getPage(downloadLink.getDownloadURL()); if (br.containsHTML("(nodata\\.png\"|<title>Videos \\| )")) throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND); String filename = br.getRegex(">Back to main page</a></div>(.*?)</h2>").getMatch(0); if (filename == null) filename = br.getRegex("<title>(.*?) \\| Videos \\| ").getMatch(0); if (filename == null) throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); if (br.containsHTML(VIDEOUNAVAILABLE)) { // Don't set final filename in this case, it's set once the video is // downloadable again! downloadLink.setName(Encoding.htmlDecode(filename) + ".flv"); downloadLink .getLinkStatus() .setStatusText( JDL.L("plugins.hoster.groups.videobeingencoded", VIDEOUNAVAILABLEUSERTEXT)); return AvailableStatus.TRUE; } DLLINK = br.getRegex("addParam\\(\\'flashvars\\',\\'\\&file=(http://.*?)\\'").getMatch(0); if (DLLINK == null) throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); DLLINK = Encoding.htmlDecode(DLLINK); DLLINK = Encoding.urlDecode(DLLINK, true); filename = filename.trim(); Browser br2 = br.cloneBrowser(); br2.setFollowRedirects(false); br2.getPage(DLLINK); DLLINK = br2.getRedirectLocation(); if (DLLINK == null) throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); downloadLink.setFinalFileName( Encoding.htmlDecode(filename) + DLLINK.substring(DLLINK.length() - 4, DLLINK.length())); URLConnectionAdapter con = null; try { con = br2.openGetConnection(DLLINK); if (!con.getContentType().contains("html") && con.getLongContentLength() != 0) { downloadLink.setDownloadSize(con.getLongContentLength()); } else { throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND); } return AvailableStatus.TRUE; } finally { try { con.disconnect(); } catch (Throwable e) { } } }
/** * creates a offline link, with filename, with logger and comment message. * * @param link * @param filename * @param message * @since JD2 * @author raztoki */ protected DownloadLink createOfflinelink( final String link, final String filename, final String message) { final DownloadLink dl = new DownloadLink( null, null, getHost(), "directhttp://" + Encoding.urlDecode(link, true), true); dl.setProperty("OFFLINE", true); dl.setAvailable(false); if (filename != null) { dl.setName(filename.trim()); } if (message != null) { dl.setComment(message); logger.info("Offline Link: " + link + " :: " + message); } else { logger.info("Offline Link: " + link); } return dl; }
@Override public AvailableStatus requestFileInformation(DownloadLink downloadLink) throws Exception { this.setBrowserExclusive(); br.getPage(downloadLink.getDownloadURL()); if (br.containsHTML("No htmlCode read")) { throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND); } dllink = br.getRegex("url: '(http[^']+(videobug\\.net|play44\\.net)%2Fvideos[^']+)").getMatch(0); if (dllink == null) { throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); } dllink = Encoding.urlDecode(dllink, false); Browser br2 = br.cloneBrowser(); // In case the link redirects to the finallink br2.setFollowRedirects(true); URLConnectionAdapter con = null; try { con = br2.openGetConnection(dllink); // only way to check for made up links... or offline is here if (con.getResponseCode() == 404) { throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND); } if (!con.getContentType().contains("html")) { downloadLink.setFinalFileName(getFileNameFromHeader(con)); downloadLink.setDownloadSize(con.getLongContentLength()); } else { throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND); } return AvailableStatus.TRUE; } finally { try { con.disconnect(); } catch (Throwable e) { } } }
@Override public ArrayList<DownloadLink> decryptIt( final CryptedLink param, final ProgressController progress) throws Exception { synchronized (LOCK) { PROGRESS = progress; final ArrayList<DownloadLink> decryptedLinks = new ArrayList<DownloadLink>(); final String parameter = correctCryptedLink(param.toString()); setBrowserExclusive(); br.setFollowRedirects(true); br.getHeaders().put("User-Agent", UA); /* Handle Captcha and/or password */ handleCaptchaAndPassword(parameter, param); if (!br.getURL().contains("relink.us/")) { try { validateLastChallengeResponse(); } catch (final Throwable e) { } logger.info("Link offline: " + parameter); return decryptedLinks; } if (br.containsHTML("<title>404</title>")) { logger.info("Link offline: " + parameter); return decryptedLinks; } if (ALLFORM != null && ALLFORM.getRegex("password").matches()) { throw new DecrypterException(DecrypterException.PASSWORD); } if (ALLFORM != null && ALLFORM.getRegex("captcha").matches()) { throw new DecrypterException(DecrypterException.CAPTCHA); } final String page = br.toString(); progress.setRange(0); final String title = br.getRegex("shrink\"><th>(Titel|Baslik|Title)</th><td>(.*?)</td></tr>").getMatch(1); FilePackage fp = null; if (title != null && title.trim().length() > 0) { fp = FilePackage.getInstance(); fp.setName(title); fp.setProperty("ALLOW_MERGE", true); } /* use cnl2 button if available */ String cnlUrl = "http://127\\.0\\.0\\.1:9666/flash/addcrypted2"; if (br.containsHTML(cnlUrl)) { final Browser cnlbr = br.cloneBrowser(); Form cnlForm = null; for (Form f : cnlbr.getForms()) { if (f.containsHTML(cnlUrl)) { cnlForm = f; } } if (cnlForm != null) { if (System.getProperty("jd.revision.jdownloaderrevision") != null) { String jk = cnlbr.getRegex("<input type=\"hidden\" name=\"jk\" value=\"([^\"]+)\"").getMatch(0); HashMap<String, String> infos = new HashMap<String, String>(); infos.put( "crypted", Encoding.urlDecode(cnlForm.getInputField("crypted").getValue(), false)); infos.put("jk", jk); String source = cnlForm.getInputField("source").getValue(); if (StringUtils.isEmpty(source)) { source = parameter.toString(); } else { source = Encoding.urlDecode(source, true); } infos.put("source", source); String json = JSonStorage.toString(infos); final DownloadLink dl = createDownloadlink( "http://dummycnl.jdownloader.org/" + HexFormatter.byteArrayToHex(json.getBytes("UTF-8"))); if (fp != null) { fp.add(dl); } try { distribute(dl); } catch (final Throwable e) { /* does not exist in 09581 */ } decryptedLinks.add(dl); return decryptedLinks; } else { String jk = cnlbr.getRegex("<input type=\"hidden\" name=\"jk\" value=\"([^\"]+)\"").getMatch(0); cnlForm.remove("jk"); cnlForm.put("jk", (jk != null ? jk.replaceAll("\\+", "%2B") : "nothing")); try { cnlbr.submitForm(cnlForm); if (cnlbr.containsHTML("success")) { return decryptedLinks; } if (cnlbr.containsHTML("^failed")) { logger.warning( "relink.us: CNL2 Postrequest was failed! Please upload now a logfile, contact our support and add this loglink to your bugreport!"); logger.warning("relink.us: CNL2 Message: " + cnlbr.toString()); } } catch (Throwable e) { logger.info("relink.us: ExternInterface(CNL2) is disabled!"); } } } } if (!br.containsHTML("download.php\\?id=[a-f0-9]+") && !br.containsHTML("getFile\\(")) { return null; } if (!decryptContainer(page, parameter, "dlc", decryptedLinks)) { if (!decryptContainer(page, parameter, "ccf", decryptedLinks)) { decryptContainer(page, parameter, "rsdf", decryptedLinks); } } /* Webdecryption */ if (decryptedLinks.isEmpty()) { decryptLinks(decryptedLinks, param); final String more_links[] = new Regex( page, Pattern.compile( "<a href=\"(go\\.php\\?id=[a-zA-Z0-9]+\\&seite=\\d+)\">", Pattern.CASE_INSENSITIVE)) .getColumn(0); for (final String link : more_links) { br.getPage("http://relink.us/" + link); decryptLinks(decryptedLinks, param); } } if (decryptedLinks.isEmpty() && br.containsHTML(cnlUrl)) { throw new DecrypterException("CNL2 only, open this link in Browser"); } try { validateLastChallengeResponse(); } catch (final Throwable e) { } if (fp != null) { fp.addLinks(decryptedLinks); } return decryptedLinks; } }
public List<YouTubeDownloadLink> decrypt(String videoUrl) throws Exception { this.possibleconverts = new HashMap<DestinationFormat, ArrayList<Info>>(); List<YouTubeDownloadLink> decryptedLinks = new LinkedList<YouTubeDownloadLink>(); String param = videoUrl; String parameter = param.toString().replace("watch#!v", "watch?v"); parameter = parameter.replaceFirst("(verify_age\\?next_url=\\/?)", ""); parameter = parameter.replaceFirst("(%3Fv%3D)", "?v="); parameter = parameter.replaceFirst("(watch\\?.*?v)", "watch?v"); parameter = parameter.replaceFirst("/embed/", "/watch?v="); parameter = parameter.replaceFirst("https", "http"); this.br.setFollowRedirects(true); this.br.setCookiesExclusive(true); this.br.clearCookies("youtube.com"); br.setCookie("http://youtube.com", "PREF", "hl=en-GB"); if (parameter.contains("watch#")) { parameter = parameter.replace("watch#", "watch?"); } if (parameter.contains("v/")) { String id = new Regex(parameter, "v/([a-z\\-_A-Z0-9]+)").getMatch(0); if (id != null) parameter = "http://www.youtube.com/watch?v=" + id; } ArrayList<String> linkstodecrypt = new ArrayList<String>(); boolean prem = false; // boolean multiple_videos = false; // parameter = new Regex(parameter, // "(http://www\\.youtube\\.com/watch\\?v=[a-z\\-_A-Z0-9]+).*?").getMatch(0); // Handle single video linkstodecrypt.add(parameter); // multiple_videos = false; boolean fast = false; final boolean best = false; final AtomicBoolean mp3 = new AtomicBoolean(false); final AtomicBoolean flv = new AtomicBoolean(false); /* http://en.wikipedia.org/wiki/YouTube */ final HashMap<Integer, Object[]> ytVideo = new HashMap<Integer, Object[]>() { private static final long serialVersionUID = -3028718522449785181L; { boolean mp4 = true; boolean webm = true; boolean threegp = false; if (mp3.get() == false && mp4 == false && webm == false && flv.get() == false && threegp == false) { /* if no container is selected, then everything is enabled */ mp3.set(true); mp4 = true; webm = true; flv.set(true); threegp = true; } boolean q240p = true; boolean q360p = true; boolean q480p = true; boolean q720p = true; boolean q1080p = true; boolean qOriginal = false; // **** FLV ***** if (mp3.get()) { this.put(0, new Object[] {DestinationFormat.AUDIOMP3, "H.263", "MP3", "Mono"}); this.put(5, new Object[] {DestinationFormat.AUDIOMP3, "H.263", "MP3", "Stereo"}); this.put(6, new Object[] {DestinationFormat.AUDIOMP3, "H.263", "MP3", "Mono"}); } if (flv.get() || best) { if (q240p || best) { // video bit rate @ 0.25Mbit/second this.put( 5, new Object[] {DestinationFormat.VIDEOFLV, "H.263", "MP3", "Stereo", "240p"}); // video bit rate @ 0.8Mbit/second this.put( 6, new Object[] {DestinationFormat.VIDEOFLV, "H.263", "MP3", "Stereo", "240p"}); } if (q360p || best) { this.put( 34, new Object[] {DestinationFormat.VIDEOFLV, "H.264", "AAC", "Stereo", "360p"}); } if (q480p || best) { this.put( 35, new Object[] {DestinationFormat.VIDEOFLV, "H.264", "AAC", "Stereo", "480p"}); } } // **** 3GP ***** if ((threegp && q240p) || best) { this.put( 13, new Object[] {DestinationFormat.VIDEO3GP, "H.263", "AAC", "Mono", "240p"}); this.put( 36, new Object[] {DestinationFormat.VIDEO3GP, "H.264", "AAC", "Stereo", "240p"}); } // **** MP4 ***** if (mp4 || best) { if (q240p || best) { this.put( 133, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "240p"}); } if (q480p || best) { this.put( 135, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "480p"}); } if (q360p || best) { // 270p / 360p this.put( 18, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "360p"}); this.put( 134, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "360p"}); } if (q720p || best) { this.put( 136, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "720p"}); this.put( 22, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "720p"}); } if (q1080p || best) { this.put( 137, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "1080p"}); this.put( 37, new Object[] {DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "1080"}); } if (qOriginal || best) { this.put( 38, new Object[] { DestinationFormat.VIDEOMP4, "H.264", "AAC", "Stereo", "Original" }); } } // **** WebM ***** if (webm || best) { if (q360p || best) { this.put( 43, new Object[] {DestinationFormat.VIDEOWEBM, "VP8", "Vorbis", "Stereo", "360p"}); } if (q480p || best) { this.put( 44, new Object[] {DestinationFormat.VIDEOWEBM, "VP8", "Vorbis", "Stereo", "480p"}); } if (q720p || best) { this.put( 45, new Object[] {DestinationFormat.VIDEOWEBM, "VP8", "Vorbis", "Stereo", "720p"}); } if (q1080p || best) { this.put( 46, new Object[] {DestinationFormat.VIDEOWEBM, "VP8", "Vorbis", "Stereo", "1080p"}); } } } }; // Force fast linkcheck if there are more then 20 videos in queue. if (linkstodecrypt.size() > 20) fast = true; for (String url : linkstodecrypt) { // Make an little sleep to prevent DDoS Thread.sleep(25); try { this.possibleconverts.clear(); verifyAge = false; final HashMap<Integer, String[]> LinksFound = this.getLinks(url, prem, this.br, 0); String error = br.getRegex( "<div id=\"unavailable\\-message\" class=\"\">[\t\n\r ]+<span class=\"yt\\-alert\\-vertical\\-trick\"></span>[\t\n\r ]+<div class=\"yt\\-alert\\-message\">([^<>\"]*?)</div>") .getMatch(0); // Removed due wrong offline detection // if (error == null) error = // br.getRegex("<div class=\"yt\\-alert\\-message\">(.*?)</div>").getMatch(0); if (error == null) error = br.getRegex("\\&reason=([^<>\"/]*?)\\&").getMatch(0); if (br.containsHTML(UNSUPPORTEDRTMP)) error = "RTMP video download isn't supported yet!"; if ((LinksFound == null || LinksFound.isEmpty()) && error != null) { error = Encoding.urlDecode(error, false); LOG.info("Video unavailable: " + url); LOG.info("Reason: " + error.trim()); continue; } if (LinksFound == null || LinksFound.isEmpty()) { if (linkstodecrypt.size() == 1) { if (verifyAge || this.br.getURL().toLowerCase(Locale.US).indexOf("youtube.com/get_video_info?") != -1 && !prem) { throw new IOException( "Can't download this video with FrostWire, age verification required from youtube."); } LOG.info("Video unavailable: " + url); continue; } else { continue; } } /* First get the filename */ String YT_FILENAME = ""; if (LinksFound.containsKey(-1)) { YT_FILENAME = LinksFound.get(-1)[0]; LinksFound.remove(-1); } /* check for wished formats first */ if (best) { // 1080p if (LinksFound.get(37) != null) { String[] temp = LinksFound.get(37); LinksFound.clear(); LinksFound.put(37, temp); // 720p } else if (LinksFound.get(45) != null || LinksFound.get(22) != null) { String[] temp1 = LinksFound.get(45); String[] temp2 = LinksFound.get(22); LinksFound.clear(); if (temp1 != null) LinksFound.put(45, temp1); if (temp2 != null) LinksFound.put(22, temp2); // 480p } else if (LinksFound.get(35) != null) { String[] temp = LinksFound.get(35); LinksFound.clear(); LinksFound.put(35, temp); // 360p } else if (LinksFound.get(43) != null || LinksFound.get(18) != null || LinksFound.get(34) != null) { String[] temp1 = LinksFound.get(43); String[] temp2 = LinksFound.get(18); String[] temp3 = LinksFound.get(34); LinksFound.clear(); if (temp1 != null) LinksFound.put(43, temp1); if (temp2 != null) LinksFound.put(18, temp2); if (temp3 != null) LinksFound.put(34, temp3); // 240p } else if (LinksFound.get(13) != null || LinksFound.get(17) != null || LinksFound.get(5) != null) { String[] temp1 = LinksFound.get(13); String[] temp2 = LinksFound.get(17); String[] temp3 = LinksFound.get(5); LinksFound.clear(); if (temp1 != null) LinksFound.put(13, temp1); if (temp2 != null) LinksFound.put(17, temp2); if (temp3 != null) LinksFound.put(5, temp3); } else { // Original String[] temp = LinksFound.get(38); LinksFound.clear(); LinksFound.put(38, temp); } } String dlLink = ""; String vQuality = ""; DestinationFormat cMode = null; for (final Integer format : LinksFound.keySet()) { if (ytVideo.containsKey(format)) { cMode = (DestinationFormat) ytVideo.get(format)[0]; vQuality = "(" + LinksFound.get(format)[1] + "_" + ytVideo.get(format)[1] + "-" + ytVideo.get(format)[2] + ")"; } else { cMode = DestinationFormat.UNKNOWN; vQuality = "(" + LinksFound.get(format)[1] + "_" + format + ")"; /* * we do not want to download unknown formats at the * moment */ continue; } dlLink = LinksFound.get(format)[0]; // Skip MP3 but handle 240p flv if (!(format == 5 && mp3.get() && !flv.get())) { try { if (fast) { this.addtopos(cMode, dlLink, 0, vQuality, format); } else if (this.br.openGetConnection(dlLink).getResponseCode() == 200) { Thread.sleep(200); this.addtopos( cMode, dlLink, this.br.getHttpConnection().getLongContentLength(), vQuality, format); } } catch (final Throwable e) { e.printStackTrace(); } finally { try { this.br.getHttpConnection().disconnect(); } catch (final Throwable e) { } } } // Handle MP3 if ((format == 0 || format == 5 || format == 6) && mp3.get()) { try { if (fast) { this.addtopos(DestinationFormat.AUDIOMP3, dlLink, 0, "", format); } else if (this.br.openGetConnection(dlLink).getResponseCode() == 200) { Thread.sleep(200); this.addtopos( DestinationFormat.AUDIOMP3, dlLink, this.br.getHttpConnection().getLongContentLength(), "", format); } } catch (final Throwable e) { e.printStackTrace(); } finally { try { this.br.getHttpConnection().disconnect(); } catch (final Throwable e) { } } } } for (final Entry<DestinationFormat, ArrayList<Info>> next : this.possibleconverts.entrySet()) { final DestinationFormat convertTo = next.getKey(); for (final Info info : next.getValue()) { // final DownloadLink thislink = this.createDownloadlink(info.link.replaceFirst("http", // "httpJDYoutube")); String link = info.link; // thislink.setBrowserUrl(parameter); // thislink.setFinalFileName(YT_FILENAME + info.desc + convertTo.getExtFirst()); long size = info.size; String name = null; if (convertTo != DestinationFormat.AUDIOMP3) { name = YT_FILENAME + info.desc + convertTo.getExtFirst(); name = FileUtils.getValidFileName(name); } else { /* * because demuxer will fail when mp3 file already * exists */ // name = YT_FILENAME + info.desc + ".tmp"; // thislink.setProperty("name", name); } // thislink.setProperty("convertto", convertTo.name()); // thislink.setProperty("videolink", parameter); // thislink.setProperty("valid", true); // thislink.setProperty("fmtNew", info.fmt); // thislink.setProperty("LINKDUPEID", name); decryptedLinks.add(new YouTubeDownloadLink(name, size, link, info.fmt)); } } } catch (final IOException e) { this.br.getHttpConnection().disconnect(); LOG.warn("Exception occurred", e); // return null; } } return decryptedLinks; }
private HashMap<Integer, String[]> parseLinks( Browser br, final String videoURL, String YT_FILENAME, boolean ythack, boolean tryGetDetails) throws InterruptedException, IOException { final HashMap<Integer, String[]> links = new HashMap<Integer, String[]>(); String html5_fmt_map = br.getRegex("\"html5_fmt_map\": \\[(.*?)\\]").getMatch(0); if (html5_fmt_map != null) { String[] html5_hits = new Regex(html5_fmt_map, "\\{(.*?)\\}").getColumn(0); if (html5_hits != null) { for (String hit : html5_hits) { String hitUrl = new Regex(hit, "url\": \"(http:.*?)\"").getMatch(0); String hitFmt = new Regex(hit, "itag\": (\\d+)").getMatch(0); String hitQ = new Regex(hit, "quality\": \"(.*?)\"").getMatch(0); if (hitUrl != null && hitFmt != null && hitQ != null) { hitUrl = unescape(hitUrl.replaceAll("\\\\/", "/")); links.put( Integer.parseInt(hitFmt), new String[] {Encoding.htmlDecode(Encoding.urlDecode(hitUrl, true)), hitQ}); } } } } else { /* new format since ca. 1.8.2011 */ html5_fmt_map = br.getRegex("\"url_encoded_fmt_stream_map\": \"(.*?)\"").getMatch(0); if (html5_fmt_map == null) { html5_fmt_map = br.getRegex("url_encoded_fmt_stream_map=(.*?)(&|$)").getMatch(0); if (html5_fmt_map != null) { html5_fmt_map = html5_fmt_map.replaceAll("%2C", ","); if (!html5_fmt_map.contains("url=")) { html5_fmt_map = html5_fmt_map.replaceAll("%3D", "="); html5_fmt_map = html5_fmt_map.replaceAll("%26", "&"); } } } if (html5_fmt_map != null && !html5_fmt_map.contains("signature") && !html5_fmt_map.contains("sig") && !html5_fmt_map.contains("s=")) { Thread.sleep(5000); br.clearCookies("youtube.com"); return null; } if (html5_fmt_map != null) { HashMap<Integer, String[]> ret = parseLinks(html5_fmt_map, false); if (ret.size() == 0) return links; links.putAll(ret); // if (false) { // /* not playable by vlc */ // /* check for adaptive fmts */ // String adaptive = br.getRegex("\"adaptive_fmts\": // \"(.*?)\"").getMatch(0); // ret = parseLinks(adaptive, true); // links.putAll(ret); // } } else { if (br.containsHTML("reason=Unfortunately")) return null; if (tryGetDetails == true) { br.getPage( "http://www.youtube.com/get_video_info?el=detailpage&video_id=" + getVideoID(videoURL)); return parseLinks(br, videoURL, YT_FILENAME, ythack, false); } else { return null; } } } /* normal links */ final HashMap<String, String> fmt_list = new HashMap<String, String>(); String fmt_list_str = ""; if (ythack) { fmt_list_str = (br.getMatch("&fmt_list=(.+?)&") + ",").replaceAll("%2F", "/").replaceAll("%2C", ","); } else { fmt_list_str = (br.getMatch("\"fmt_list\":\\s+\"(.+?)\",") + ",").replaceAll("\\\\/", "/"); } final String fmt_list_map[][] = new Regex(fmt_list_str, "(\\d+)/(\\d+x\\d+)/\\d+/\\d+/\\d+,").getMatches(); for (final String[] fmt : fmt_list_map) { fmt_list.put(fmt[0], fmt[1]); } if (links.size() == 0 && ythack) { /* try to find fallback links */ String urls[] = br.getRegex("url%3D(.*?)($|%2C)").getColumn(0); int index = 0; for (String vurl : urls) { String hitUrl = new Regex(vurl, "(.*?)%26").getMatch(0); String hitQ = new Regex(vurl, "%26quality%3D(.*?)%").getMatch(0); if (hitUrl != null && hitQ != null) { hitUrl = unescape(hitUrl.replaceAll("\\\\/", "/")); if (fmt_list_map.length >= index) { links.put( Integer.parseInt(fmt_list_map[index][0]), new String[] {Encoding.htmlDecode(Encoding.urlDecode(hitUrl, false)), hitQ}); index++; } } } } for (Integer fmt : links.keySet()) { String fmt2 = fmt + ""; if (fmt_list.containsKey(fmt2)) { String Videoq = links.get(fmt)[1]; final Integer q = Integer.parseInt(fmt_list.get(fmt2).split("x")[1]); if (fmt == 17) { Videoq = "144p"; } else if (fmt == 40) { Videoq = "240p Light"; } else if (q > 1080) { Videoq = "Original"; } else if (q > 720) { Videoq = "1080p"; } else if (q > 576) { Videoq = "720p"; } else if (q > 480) { Videoq = "520p"; } else if (q > 360) { Videoq = "480p"; } else if (q > 240) { Videoq = "360p"; } else { Videoq = "240p"; } links.get(fmt)[1] = Videoq; } } if (YT_FILENAME != null && links != null && !links.isEmpty()) { links.put(-1, new String[] {YT_FILENAME}); } return links; }
protected DownloadLink createDownloadlink(String link, boolean urlDecode) { return new DownloadLink( null, null, getHost(), urlDecode ? Encoding.urlDecode(link, true) : link, true); }