I wrote an Android app that plays YouTube/Local media on VLC attached to a big screen TV last year. It was playing very nice but I always want to replace the VLC laptop with something more elegant. I was really excited when Chromecast was finally released with an official SDK. I too ran into the same problem when trying to launch YouTube receiver app to play YouTube video so I decided to delve into how VLC was able to do that (Is open source great :)) I found out that the YouTube video ID is just a JavaScript page with lots of stuff embedded inside. The trick is to pull out the correct info from it. Unfortunately, the VLC script is written in Lua so I spent a couple weeks learning enough Lua to navigate my way around the Lua script. You can google youtube.lua for the source code of the script.
I rewrote the script in Java and was able to modify CastVideos Android to play YouTube video at ease. Note that since Chromecast can only play mp4 video container format, video in other format may not play.
Here is my test code if anyone is interested. You can test the URL using CastHelloVideo-chrome load custom media.
Enjoy,
Danh
package com.dql.urlexplorer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class UrlExplore {
private static final String URL_ENCODED_STREAM_MAP = "\"url_encoded_fmt_stream_map\":";
private static final String VIDEO_TITLE_KEYWORD = "<meta name=\"title\"";
private static final String VIDEO_DESCRIPTION_KEYWORD = "<meta name=\"description\"";
private static final String VIDEO_THUMBNAIL_KEYWORD = "<meta property=\"og:image\"" ;
private static final String CONTENT_VALUE_KEYWORD = "content=\"";
//private static final String TEST_URL = "http://www.youtube.com/watch?v=JtyCM4BTbYo";
private static final String YT_UTRL_PREFIX = "http://www.youtube.com/watch?v=";
public static void main(String[] args) throws IOException {
while (true) {
String videoId = getVideoIdFromUser();
String urlSite = YT_UTRL_PREFIX + videoId;
System.out.println("URL = " + urlSite);
System.out.println("===============================================================");
System.out.println("Getting video site content");
System.out.println("===============================================================");
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpGet httpget = new HttpGet(urlSite);
System.out.println("Executing request " + httpget.getRequestLine());
// Create a custom response handler
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
public String handleResponse(
final HttpResponse response) throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
String responseBody = httpclient.execute(httpget, responseHandler);
if (responseBody.contains(VIDEO_TITLE_KEYWORD)) {
// video title
int titleStart = responseBody.indexOf(VIDEO_TITLE_KEYWORD);
StringBuilder title = new StringBuilder();
char ch;
do {
ch = responseBody.charAt(titleStart++);
title.append(ch);
}
while (ch != '>');
String videoTitle = getKeyContentValue(title.toString());
System.out.println("Video Title = " + videoTitle);
}
if (responseBody.contains(VIDEO_DESCRIPTION_KEYWORD)) {
// video description
int descStart = responseBody.indexOf(VIDEO_DESCRIPTION_KEYWORD);
StringBuilder desc = new StringBuilder();
char ch;
do {
ch = responseBody.charAt(descStart++);
desc.append(ch);
}
while (ch != '>');
String videoDesc = getKeyContentValue(desc.toString());
System.out.println("Video Description = " + videoDesc);
}
if (responseBody.contains(VIDEO_THUMBNAIL_KEYWORD)) {
// video thumbnail
int thumbnailStart = responseBody.indexOf(VIDEO_THUMBNAIL_KEYWORD);
StringBuilder thumbnailURL = new StringBuilder();
char ch;
do {
ch = responseBody.charAt(thumbnailStart++);
thumbnailURL.append(ch);
}
while (ch != '>');
String videoThumbnail= getKeyContentValue(thumbnailURL.toString());
System.out.println("Video Thumbnail = " + videoThumbnail);
}
if (responseBody.contains(URL_ENCODED_STREAM_MAP)) {
// find the string we are looking for
int start = responseBody.indexOf(URL_ENCODED_STREAM_MAP) + URL_ENCODED_STREAM_MAP.length() + 1; // is the opening "
String urlMap = responseBody.substring(start);
int end = urlMap.indexOf("\"");
if (end > 0) {
urlMap = urlMap.substring(0, end);
}
String path = getURLEncodedStream(urlMap);
System.out.println("Video URL = " + path);
}
}
finally {
httpclient.close();
}
System.out.println( "===============================================================");
System.out.println("Done: ");
System.out.println("===============================================================");
}
}
static String getURLEncodedStream(String stream) throws UnsupportedEncodingException {
// replace all the \u0026 with &
String str = stream.replace("\\u0026", "&");
//str = java.net.URLDecoder.decode(stream, "UTF-8");
//System.out.println("Raw URL map = " + str);
String urlMap = str.substring(str.indexOf("url=http") + 4);
// search urlMap until we see either a & or ,
StringBuilder sb = new StringBuilder();
for (int i = 0; i < urlMap.length(); i++) {
if ((urlMap.charAt(i) == '&') || (urlMap.charAt(i) == ','))
break;
else
sb.append(urlMap.charAt(i));
}
//System.out.println(java.net.URLDecoder.decode(sb.toString(),"UTF-8"));
return java.net.URLDecoder.decode(sb.toString(),"UTF-8");
}
static String getKeyContentValue(String str) {
StringBuilder contentStr = new StringBuilder();
int contentStart = str.indexOf(CONTENT_VALUE_KEYWORD) + CONTENT_VALUE_KEYWORD.length();
if (contentStart > 0) {
char ch;
while (true) {
ch = str.charAt(contentStart++);
if (ch == '\"')
break;
contentStr.append(ch);
}
}
try {
return java.net.URLDecoder.decode(contentStr.toString(),"UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*
* Prompt the user to enter a video ID.
*/
private static String getVideoIdFromUser() throws IOException {
String videoId = "";
System.out.print("Please enter a YouTube video Id: ");
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
videoId = bReader.readLine();
if (videoId.length() < 1) {
// Exit if the user doesn't provide a value.
System.out.print("Video Id can't be empty! Exiting program");
System.exit(1);
}
return videoId;
}
}`enter code here`