2011-01-15 13 views
14

Quiero acceder a un video de youtube y reproducir usando mi propio reproductor multimedia. Puedo obtener las propiedades del video (título, URL, etc.) usando la API de datos de youtube. ¿Puedo acceder a la transmisión del video y usar mi propio Reproductor de Medios (como el Reproductor de Android Media) para jugarlo? Estoy probando todo esto en JAVA.API de datos de Youtube: Obtenga acceso a la transmisión multimedia y reproducción (JAVA)

Gracias de antemano ... :)

+0

Javascript Nishant – sharath

+1

@Nishant es que vale la pena comentar que para la pequeña corrección insignificante? – Petruza

Respuesta

8

No puede. Mire aquí para leer más sobre lo que la API podría manejar: YoutubeAPI
Si pudiera obtener un InputStream sobre eso, Google no obtendría ningún dinero para publicidad en absoluto.

Pero podría analizar la página de la URL de video que obtuvo de la API y buscar el enlace de video real dentro de las etiquetas de flash.

11
/** 
* This work is licensed under a Creative Commons Attribution 3.0 Unported 
* License (http://creativecommons.org/licenses/by/3.0/). This work is placed 
* into the public domain by the author. 
*/ 
import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.Reader; 
import java.io.StringWriter; 
import java.io.UnsupportedEncodingException; 
import java.io.Writer; 
import java.net.URI; 
import java.net.URISyntaxException; 
import java.text.DecimalFormat; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Scanner; 
import java.util.logging.Formatter; 
import java.util.logging.Handler; 
import java.util.logging.Level; 
import java.util.logging.LogRecord; 
import java.util.logging.Logger; 
import java.util.regex.Pattern; 

import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse; 
import org.apache.http.NameValuePair; 
import org.apache.http.client.CookieStore; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.protocol.ClientContext; 
import org.apache.http.client.utils.URIUtils; 
import org.apache.http.client.utils.URLEncodedUtils; 
import org.apache.http.impl.client.BasicCookieStore; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.message.BasicNameValuePair; 
import org.apache.http.protocol.BasicHttpContext; 
import org.apache.http.protocol.HttpContext; 

/** 
* Locally download a YouTube.com video. 
*/ 
public class JavaYoutubeDownloader extends Formatter { 

private static final String scheme = "http"; 
private static final String host = "www.youtube.com"; 
private static final String YOUTUBE_WATCH_URL_PREFIX = scheme + "://" + host + "/watch?v="; 
private static final String ERROR_MISSING_VIDEO_ID = "Missing video id. Extract from " + YOUTUBE_WATCH_URL_PREFIX + "VIDEO_ID"; 
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"; 
private static final String DEFAULT_ENCODING = "UTF-8"; 
private static final String newline = System.getProperty("line.separator"); 
private static final Logger log = Logger.getLogger(JavaYoutubeDownloader.class.getCanonicalName()); 
private static final Logger rootlog = Logger.getLogger(""); 
private static final Pattern commaPattern = Pattern.compile(","); 
private static final Pattern pipePattern = Pattern.compile("\\|"); 
private static final char[] ILLEGAL_FILENAME_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' }; 
private static final int BUFFER_SIZE = 2048; 
private static final DecimalFormat commaFormatNoPrecision = new DecimalFormat("###,###"); 
private static final double ONE_HUNDRED = 100; 
private static final double KB = 1024; 

private void usage(String error) { 
    if (error != null) { 
    System.err.println("Error: " + error); 
    } 
    System.err.println("usage: JavaYoutubeDownload VIDEO_ID"); 
    System.err.println(); 
    System.err.println("Options:"); 
    System.err.println("\t[-dir DESTINATION_DIR] - Specify output directory."); 
    System.err.println("\t[-format FORMAT] - Format number" + newline + "\t\tSee http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs"); 
    System.err.println("\t[-ua USER_AGENT] - Emulate a browser user agent."); 
    System.err.println("\t[-enc ENCODING] - Default character encoding."); 
    System.err.println("\t[-verbose] - Verbose logging for downloader component."); 
    System.err.println("\t[-verboseall] - Verbose logging for all components (e.g. HttpClient)."); 
    System.exit(-1); 
} 

public static void main(String[] args) { 
    try { 
    new JavaYoutubeDownloader().run(args); 
    } catch (Throwable t) { 
    t.printStackTrace(); 
    } 
} 

private void run(String[] args) throws Throwable { 
    setupLogging(Level.WARNING, Level.WARNING); 

    String videoId = null; 
    String outdir = "."; 
    int format = 18; 
    String encoding = DEFAULT_ENCODING; 
    String userAgent = DEFAULT_USER_AGENT; 

    for (int i = 0; i < args.length; i++) { 
    String arg = args[i]; 

    // Options start with either -, -- 
    // Do not accept Windows-style args that start with/because of abs 
    // paths on linux for file names. 
    if (arg.charAt(0) == '-') { 

    // For easier processing, convert any double dashes to 
    // single dashes 
    if (arg.length() > 1 && arg.charAt(1) == '-') { 
    arg = arg.substring(1); 
    } 

    String larg = arg.toLowerCase(); 

    // Process the option 
    if (larg.equals("-help") || larg.equals("-?") || larg.equals("-usage") || larg.equals("-h")) { 
    usage(null); 
    } else if (larg.equals("-verbose")) { 
    setupLogging(Level.ALL, Level.WARNING); 
    } else if (larg.equals("-verboseall")) { 
    setupLogging(Level.ALL, Level.ALL); 
    } else if (larg.equals("-dir")) { 
    outdir = args[++i]; 
    } else if (larg.equals("-format")) { 
    format = Integer.parseInt(args[++i]); 
    } else if (larg.equals("-ua")) { 
    userAgent = args[++i]; 
    } else if (larg.equals("-enc")) { 
    encoding = args[++i]; 
    } else { 
    usage("Unknown command line option " + args[i]); 
    } 
    } else { 
    // Non-option (i.e. does not start with -, -- 

    videoId = arg; 

    // Break if only the first non-option should be used. 
    break; 
    } 
    } 

    if (videoId == null) { 
    usage(ERROR_MISSING_VIDEO_ID); 
    } 

    log.fine("Starting"); 

    if (videoId.startsWith(YOUTUBE_WATCH_URL_PREFIX)) { 
    videoId = videoId.substring(YOUTUBE_WATCH_URL_PREFIX.length()); 
    } 
    int a = videoId.indexOf('&'); 
    if (a != -1) { 
    videoId = videoId.substring(0, a); 
    } 

    File outputDir = new File(outdir); 
    String extension = getExtension(format); 

    play(videoId, format, encoding, userAgent, outputDir, extension); 

    log.fine("Finished"); 
} 

private static String getExtension(int format) { 
    switch (format) { 
    case 18: 
    return "mp4"; 
    default: 
    throw new Error("Unsupported format " + format); 
    } 
} 

private static void play(String videoId, int format, String encoding, String userAgent, File outputdir, String extension) throws Throwable { 
    log.fine("Retrieving " + videoId); 
    List<NameValuePair> qparams = new ArrayList<NameValuePair>(); 
    qparams.add(new BasicNameValuePair("video_id", videoId)); 
    qparams.add(new BasicNameValuePair("fmt", "" + format)); 
    URI uri = getUri("get_video_info", qparams); 

    CookieStore cookieStore = new BasicCookieStore(); 
    HttpContext localContext = new BasicHttpContext(); 
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); 

    HttpClient httpclient = new DefaultHttpClient(); 
    HttpGet httpget = new HttpGet(uri); 
    if (userAgent != null && userAgent.length() > 0) { 
    httpget.setHeader("User-Agent", userAgent); 
    } 

    log.finer("Executing " + uri); 
    HttpResponse response = httpclient.execute(httpget, localContext); 
    HttpEntity entity = response.getEntity(); 
    if (entity != null && response.getStatusLine().getStatusCode() == 200) { 
    InputStream instream = entity.getContent(); 
    String videoInfo = getStringFromInputStream(encoding, instream); 
    if (videoInfo != null && videoInfo.length() > 0) { 
    List<NameValuePair> infoMap = new ArrayList<NameValuePair>(); 
    URLEncodedUtils.parse(infoMap, new Scanner(videoInfo), encoding); 
    String downloadUrl = null; 
    String filename = videoId; 

    for (NameValuePair pair : infoMap) { 
    String key = pair.getName(); 
    String val = pair.getValue(); 
    log.finest(key + "=" + val); 
    if (key.equals("title")) { 
     filename = val; 
    } else if (key.equals("fmt_url_map")) { 
     String[] formats = commaPattern.split(val); 
     boolean found = false; 
     for (String fmt : formats) { 
     String[] fmtPieces = pipePattern.split(fmt); 
     if (fmtPieces.length == 2) { 
     int pieceFormat = Integer.parseInt(fmtPieces[0]); 
     log.fine("Available format=" + pieceFormat); 
     if (pieceFormat == format) { 
     // found what we want 
     downloadUrl = fmtPieces[1]; 
     found = true; 
     break; 
     } 
     } 
     } 
     if (!found) { 
     log.warning("Could not find video matching specified format, however some formats of the video do exist (use -verbose)."); 
     } 
    } 
    } 

    filename = cleanFilename(filename); 
    if (filename.length() == 0) { 
    filename = videoId; 
    } else { 
    filename += "_" + videoId; 
    } 
    filename += "." + extension; 
    File outputfile = new File(outputdir, filename); 

    if (downloadUrl != null) { 
    downloadWithHttpClient(userAgent, downloadUrl, outputfile); 
    } else { 
    log.severe("Could not find video"); 
    } 
    } else { 
    log.severe("Did not receive content from youtube"); 
    } 
    } else { 
    log.severe("Could not contact youtube: " + response.getStatusLine()); 
    } 
} 

private static void downloadWithHttpClient(String userAgent, String downloadUrl, File outputfile) throws Throwable { 
    HttpGet httpget2 = new HttpGet(downloadUrl); 
    if (userAgent != null && userAgent.length() > 0) { 
    httpget2.setHeader("User-Agent", userAgent); 
    } 

    log.finer("Executing " + httpget2.getURI()); 
    HttpClient httpclient2 = new DefaultHttpClient(); 
    HttpResponse response2 = httpclient2.execute(httpget2); 
    HttpEntity entity2 = response2.getEntity(); 
    if (entity2 != null && response2.getStatusLine().getStatusCode() == 200) { 
    double length = entity2.getContentLength(); 
    if (length <= 0) { 
    // Unexpected, but do not divide by zero 
    length = 1; 
    } 
    InputStream instream2 = entity2.getContent(); 
    System.out.println("Writing " + commaFormatNoPrecision.format(length) + " bytes to " + outputfile); 
    if (outputfile.exists()) { 
    outputfile.delete(); 
    } 
    FileOutputStream outstream = new FileOutputStream(outputfile); 
    try { 
    byte[] buffer = new byte[BUFFER_SIZE]; 
    double total = 0; 
    int count = -1; 
    int progress = 10; 
    long start = System.currentTimeMillis(); 
    while ((count = instream2.read(buffer)) != -1) { 
    total += count; 
    int p = (int) ((total/length) * ONE_HUNDRED); 
    if (p >= progress) { 
     long now = System.currentTimeMillis(); 
     double s = (now - start)/1000; 
     int kbpers = (int) ((total/KB)/s); 
     System.out.println(progress + "% (" + kbpers + "KB/s)"); 
     progress += 10; 
    } 
    outstream.write(buffer, 0, count); 
    } 
    outstream.flush(); 
    } finally { 
    outstream.close(); 
    } 
    System.out.println("Done"); 
    } 
} 

private static String cleanFilename(String filename) { 
    for (char c : ILLEGAL_FILENAME_CHARACTERS) { 
    filename = filename.replace(c, '_'); 
    } 
    return filename; 
} 

private static URI getUri(String path, List<NameValuePair> qparams) throws URISyntaxException { 
    URI uri = URIUtils.createURI(scheme, host, -1, "/" + path, URLEncodedUtils.format(qparams, DEFAULT_ENCODING), null); 
    return uri; 
} 

private void setupLogging(Level myLevel, Level globalLevel) { 
    changeFormatter(this); 
    explicitlySetAllLogging(myLevel, globalLevel); 
} 

@Override 
public String format(LogRecord arg0) { 
    return arg0.getMessage() + newline; 
} 

private static void changeFormatter(Formatter formatter) { 
    Handler[] handlers = rootlog.getHandlers(); 
    for (Handler handler : handlers) { 
    handler.setFormatter(formatter); 
    } 
} 

private static void explicitlySetAllLogging(Level myLevel, Level globalLevel) { 
    rootlog.setLevel(Level.ALL); 
    for (Handler handler : rootlog.getHandlers()) { 
    handler.setLevel(Level.ALL); 
    } 
    log.setLevel(myLevel); 
    rootlog.setLevel(globalLevel); 
} 

private static String getStringFromInputStream(String encoding, InputStream instream) throws UnsupportedEncodingException, IOException { 
    Writer writer = new StringWriter(); 

    char[] buffer = new char[1024]; 
    try { 
    Reader reader = new BufferedReader(new InputStreamReader(instream, encoding)); 
    int n; 
    while ((n = reader.read(buffer)) != -1) { 
    writer.write(buffer, 0, n); 
    } 
    } finally { 
    instream.close(); 
    } 
    String result = writer.toString(); 
    return result; 
} 
} 

/** 
* <pre> 
* Exploded results from get_video_info: 
* 
* fexp=909302 
* allow_embed=1 
* fmt_stream_map=35|http://v9.lscache8.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=35&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=9E0A8E67154145BCADEBCF844CC155282548288F.2BBD0B2E125E3E533D07866C7AE91B38DD625D30&factor=1.25&id=4ba2193f7c9127d2||tc.v9.cache8.c.youtube.com,34|http://v6.lscache3.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=6726793A7B041E6456B52C0972596D0D58974141.42B5A0573F62B85AEA7979E5EE1ADDD47EB9E909&factor=1.25&id=4ba2193f7c9127d2||tc.v6.cache3.c.youtube.com,18|http://v12.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=AE58398D4CC4D760C682D2A5B670B4047777FFF0.952E4FC4554E786FD937E7A89140E1F79B6DD8B7&factor=1.25&id=4ba2193f7c9127d2||tc.v12.cache7.c.youtube.com,5|http://v1.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=43434DCB6CFC463FF4522D9EE7CD019FE47237B1.C60A9522E361130938663AF2DAD83A5C2821AF5C&factor=1.25&id=4ba2193f7c9127d2||tc.v1.cache7.c.youtube.com 
* fmt_url_map=35|http://v9.lscache8.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=35&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=9E0A8E67154145BCADEBCF844CC155282548288F.2BBD0B2E125E3E533D07866C7AE91B38DD625D30&factor=1.25&id=4ba2193f7c9127d2,34|http://v6.lscache3.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=6726793A7B041E6456B52C0972596D0D58974141.42B5A0573F62B85AEA7979E5EE1ADDD47EB9E909&factor=1.25&id=4ba2193f7c9127d2,18|http://v12.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=AE58398D4CC4D760C682D2A5B670B4047777FFF0.952E4FC4554E786FD937E7A89140E1F79B6DD8B7&factor=1.25&id=4ba2193f7c9127d2,5|http://v1.lscache7.c.youtube.com/videoplayback?ip=174.0.0.0&sparams=id%2Cexpire%2Cip%2Cipbits%2Citag%2Calgorithm%2Cburst%2Cfactor&fexp=909302&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1294549200&key=yt1&signature=43434DCB6CFC463FF4522D9EE7CD019FE47237B1.C60A9522E361130938663AF2DAD83A5C2821AF5C&factor=1.25&id=4ba2193f7c9127d2 
* allow_ratings=1 
* keywords=Stefan Molyneux,Luke Bessey,anarchy,stateless society,giant stone cow,the story of our unenslavement,market anarchy,voluntaryism,anarcho capitalism 
* track_embed=0 
* fmt_list=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0 
* author=lukebessey 
* muted=0 
* length_seconds=390 
* plid=AASZXXGQtTEDKwAw 
* ftoken=null 
* status=ok 
* watermark=http://s.ytimg.com/yt/swf/logo-vfl_bP6ud.swf,http://s.ytimg.com/yt/swf/hdlogo-vfloR6wva.swf 
* timestamp=1294526523 
* has_cc=False 
* fmt_map=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0 
* leanback_module=http://s.ytimg.com/yt/swfbin/leanback_module-vflJYyeZN.swf 
* hl=en_US 
* endscreen_module=http://s.ytimg.com/yt/swfbin/endscreen-vflk19iTq.swf 
* vq=auto 
* avg_rating=5.0 
* video_id=S6IZP3yRJ9I 
* token=vjVQa1PpcFNhI3jvw6hfEHivcKK-XY5gb-iszDMrooA= 
* thumbnail_url=http://i4.ytimg.com/vi/S6IZP3yRJ9I/default.jpg 
* title=The Story of Our Unenslavement - Animated 
* </pre> 
*/ 
Cuestiones relacionadas