Android App for Youtube Playlist

This tutorials is about generating an android app for your youtube Playlist.The center line of this tutorials revolves around generating an youtube playlist feed url, pasing xml file by requesting the url and extracting the video related informations.

1. Getting Youtube Playlist Url:

Using the youtube api v2 we can get the url for the playlist feed. You can study the api related documentation here.
Any way this is url format to get the playlist feed for youtube playlist.

http://gdata.youtube.com/feeds/api/playlists/“?v=2&max-results=50

When you retrieve a video feed or list of search results, YouTube returns an Atom feed that contains one tag for each video in the result set. The root XML tag in the response will be the tag. In addition to the information about the individual videos in the result set, the feed will also contain the total number of results in the list, the index of the first item in the list, the number of items in the list and other metadata about the feed.

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
    xmlns:gml='http://www.opengis.net/gml'
    xmlns:georss='http://www.georss.org/georss'
    xmlns:media='http://search.yahoo.com/mrss/'
    xmlns:batch='http://schemas.google.com/gdata/batch'
    xmlns:yt='http://gdata.youtube.com/schemas/2007'
    xmlns:gd='http://schemas.google.com/g/2005'
    gd:etag='W/&quot;CE4EQH47eCp7ImA9WxRQGEQ.&quot;'>
  <id>tag:youtube.com,2008:standardfeed:global:most_popular</id>
  <updated>2008-07-18T05:00:49.000-07:00</updated>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://gdata.youtube.com/schemas/2007#video'/>
  <title>Most Popular</title>
  <logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
  <link rel='alternate' type='text/html'
    href='https://www.youtube.com/browse?s=tr'/>
  <link rel='http://schemas.google.com/g/2005#feed'
    type='application/atom+xml'
    href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular?v=2'/>
  <link rel='http://schemas.google.com/g/2005#batch'
    type='application/atom+xml'
    href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular/batch?v=2'/>
  <link rel='self' type='application/atom+xml'
    href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular?...'/>
  <link rel='service' type='application/atomsvc+xml'
    href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular?...'/>
  <link rel='next' type='application/atom+xml'
    href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular?...'/>
  <author>
    <name>YouTube</name>
    <uri>http://www.youtube.com/</uri>
  </author>
  <generator version='2.0'
    uri='http://gdata.youtube.com/'>YouTube data API</generator>
  <openSearch:totalResults>100</openSearch:totalResults>
  <openSearch:startIndex>1</openSearch:startIndex>
  <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
  <entry gd:etag='W/&quot;C0AMRn47eCp7ImA9WxRQGUw.&quot;'>
    <id>tag:youtube,2008:video:ZTUVgYoeN_b</id>
    <published>2008-07-05T19:56:35.000-07:00</published>
    <updated>2008-07-18T07:21:59.000-07:00</updated>
    <category scheme='http://schemas.google.com/g/2005#kind'
      term='http://gdata.youtube.com/schemas/2007#video'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
      term='Shopping'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
      term='parkas'/>
    <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
      term='People' label='People'/>
    <title>Shopping for Coats</title>
    <content type='application/x-shockwave-flash'
      src='http://www.youtube.com/v/ZTUVgYoeN_b?f=gdata_standard...'/>
    <link rel='alternate' type='text/html'
      href='https://www.youtube.com/watch?v=ZTUVgYoeN_b'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
      type='application/atom+xml'
      href='https://gdata.youtube.com/feeds/api/videos/ZTUVgYoeN_b/responses?v=2'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
      type='application/atom+xml'
      href='https://gdata.youtube.com/feeds/api/videos/ZTUVgYoeN_b/ratings?v=2'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.complaints'
      type='application/atom+xml'
      href='https://gdata.youtube.com/feeds/api/videos/ZTUVgYoeN_b/complaints?v=2'/>
    <link rel='http://gdata.youtube.com/schemas/2007#video.related'
      type='application/atom+xml'
      href='https://gdata.youtube.com/feeds/api/videos/ZTUVgYoeN_b/related?v=2'/>
    <link rel='http://gdata.youtube.com/schemas/2007#mobile'
      type='text/html' href='https://m.youtube.com/details?v=ZTUVgYoeN_b'/>
    <link rel='http://gdata.youtube.com/schemas/2007#uploader'
      type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/users/_x5XG1OV2P6uZZ5FSM9Ttw?v=2'/>
    <link rel='self' type='application/atom+xml'
      href='https://gdata.youtube.com/feeds/api/standardfeeds/most_popular/v/ZTUVgYoeN_b?v=2'/>
    <author>
      <name>GoogleDevelopers</name>
      <uri>https://gdata.youtube.com/feeds/api/users/GoogleDevelopers</uri>
      <yt:userId>_x5XG1OV2P6uZZ5FSM9Ttw<</yt:userId>
    </author>
    <yt:accessControl action='comment' permission='allowed'/>
    <yt:accessControl action='commentVote' permission='allowed'/>
    <yt:accessControl action='rate' permission='allowed'/>
    <yt:accessControl action='embed' permission='allowed'/>
    <yt:accessControl action='list' permission='allowed'/>
    <yt:accessControl action='autoPlay' permission='allowed'/>
    <yt:accessControl action='syndicate' permission='allowed'/>
    <gd:comments>
      <gd:feedLink href='https://gdata.youtube.com/feeds/api/videos/ZTUVgYoeN_b/comments'
        countHint='9416'/>
    </gd:comments>
    <georss:where>
      <gml:Point>
        <gml:pos>21.37124437061831 -157.87353515625</gml:pos>
      </gml:Point>
    </georss:where>
    <yt:hd/>
    <media:group>
      <media:category label='People'
        scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>People
      </media:category>
      <media:content 
        url='http://www.youtube.com/v/ZTUVgYoeN_b?f=gdata_standard...'
        type='application/x-shockwave-flash' medium='video'
        isDefault='true' expression='full' duration='215' yt:format='5'/>
      <media:content
        url='rtsp://rtsp2.youtube.com/ChoLENy73bIAEQ1kgGDA==/0/0/0/video.3gp'
        type='video/3gpp' medium='video'
        expression='full' duration='215' yt:format='1'/>
      <media:content
        url='rtsp://rtsp2.youtube.com/ChoLENy73bIDRQ1kgGDA==/0/0/0/video.3gp'
        type='video/3gpp' medium='video'
        expression='full' duration='215' yt:format='6'/>
      <media:credit role='uploader' scheme='urn:youtube'
          yt:display='GoogleDevelopers'>GoogleDevelopers</media:credit>
      <media:description type='plain'>
        What could make for more exciting video?
      </media:description>
      <media:keywords>Shopping, parkas</media:keywords>
      <media:license type='text/html' href='http://www.youtube.com/t/terms'>youtube</media:license>
      <media:player url='https://www.youtube.com/watch?v=ZTUVgYoeN_b'/>
      <media:thumbnail url='http://img.youtube.com/vi/ZTUVgYoeN_b/2.jpg'
        height='90' width='120' time='00:00:03.500'/>
      <media:thumbnail url='http://img.youtube.com/vi/ZTUVgYoeN_b/1.jpg'
        height='90' width='120' time='00:00:01.750'/>
      <media:thumbnail url='http://img.youtube.com/vi/ZTUVgYoeN_b/3.jpg'
        height='90' width='120' time='00:00:05.250'/>
      <media:thumbnail url='http://img.youtube.com/vi/ZTUVgYoeN_b/0.jpg'
        height='360' width='480' time='00:00:03.500'/>
      <media:title type='plain'>Shopping for Coats</media:title>
      <yt:aspectRatio>widescreen</yt:aspectRatio>
      <yt:duration seconds='79'/>
      <yt:uploaded>2008-07-05T19:56:35.000-07:00</yt:uploaded>
      <yt:uploaderId>UC_x5XG1OV2P6uZZ5FSM9Ttw</yt:uploaderId>
      <yt:videoid>ZTUVgYoeN_b</yt:videoid>
    </media:group>
    <gd:rating min='1' max='5' numRaters='14763' average='4.93'/>
    <yt:recorded>2008-07-04</yt:recorded>
    <yt:statistics viewCount='383290' favoriteCount='7022'/>
    <yt:rating numDislikes='19257' numLikes='106000'/>
  </entry>
</feed>

2. Jump on to App:

As we have got the url for the playlist feed.Thus to make an app your task would be,

a. Parsing the xml feed: For parsing the xml feed we need to an xml parsing mechanism. Here we use DOM parser. Create a java file name Parser.java

package org.aynsoft.java;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import android.util.Log;

public class Parser {
	/** --------------------- Movie Search TAG --------------------- */
	private static final String TAG_GROUP = "media:group";
	private static final String TAG_TITLE = "media:title";
	private static final String TAG_MEDIA_THUMB = "media:thumbnail";
	private static final String TAG_VIDEO_ID = "yt:videoid";
	private static final String TAG_DURATION = "yt:duration";

	/** ---------------------Movie Attribute tags--------------------- */
	private static final String ATR_THUMB_NAME = "yt:name";
	private static final String ATR_THUMB_URL = "url";
	private static final String ATR_DURATION = "seconds";
	/** ---------------------Movie Attribute tags--------------------- */
	private static final String VALUE_ATR_POSTER = "poster";
	private static final String VALUE_ATR_DEFAULT = "default";
	
	

	public NodeList getResponceNodeList(String service_url) {
		String searchResponce = getHttpResponse(URI.create(service_url));
		//Log.i("url",""+service_url);
		Log.i("responce",""+searchResponce);
		Document doc;
		NodeList items = null;
		if (searchResponce != null) {
			Log.i("Not null","executed");
			try {
				doc = this.getDomElement(searchResponce);
				items = doc.getElementsByTagName("entry");				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return items;
	}

	public VideoDetail getResult(NodeList searchresult, int position) {
		VideoDetail result = new VideoDetail();
		try {
			Element e = (Element) searchresult.item(position);
			NodeList list=e.getElementsByTagName(TAG_GROUP);
			Element e1=(Element)list.item(0);
			String title = this.getValue(e1, TAG_TITLE);
			String video_id = this.getValue(e1, TAG_VIDEO_ID);
			String image_url=this.getImageUrlAttributeValue(TAG_MEDIA_THUMB,
					ATR_THUMB_NAME,VALUE_ATR_POSTER, e1);
			if(image_url==null){
				image_url=this.getImageUrlAttributeValue(TAG_MEDIA_THUMB,
						ATR_THUMB_NAME,VALUE_ATR_DEFAULT, e1);
			}
			String duration=this.getAttributeValue(e1, TAG_DURATION, ATR_DURATION);			
			result.setTitle(title);
			result.setVideo_id(video_id);
			result.setDuration(duration);
			result.setIcon_url(image_url);
			
			Log.i("title",""+title);
			Log.i("id",""+video_id);
			Log.i("duration",""+duration);
			Log.i("image_url",""+image_url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	public String getImageUrlAttributeValue(String tag,String attribute_key,String attribute_value,Element e){
		NodeList list=e.getElementsByTagName(tag);
		String url=null;
		for(int i=0;i<list .getLength();i++){
			Element element=(Element)list.item(i);
			if(element.getAttribute(attribute_key).equals(attribute_value)){
				url=element.getAttribute(ATR_THUMB_URL);
				return url;
			}
		}
		return url;
	}

	public String getAttributeValue(Element e,String tag,String attribute){
		String atr=null;
		NodeList list=e.getElementsByTagName(tag);
		Element element=(Element)list.item(0);
		atr=element.getAttribute(attribute);		
		return atr;
	}
	
	

	/** In app reused functions */

	private String getUrlContents(String theUrl) {
		
		StringBuilder content = new StringBuilder();
		try {
			URL url = new URL(theUrl);
			URLConnection urlConnection = url.openConnection();
			BufferedReader bufferedReader = new BufferedReader(
					new InputStreamReader(urlConnection.getInputStream()), 8);
			String line;
			while ((line = bufferedReader.readLine()) != null) {
				content.append(line + "");
			}
			bufferedReader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return content.toString();
		
		
	}
	public static String getHttpResponse(URI uri) {
	    Log.d("Parser", "Going to make a get request");
	    StringBuilder response = new StringBuilder();
	    try {
	        HttpGet get = new HttpGet();
	        get.setURI(uri);
	        DefaultHttpClient httpClient = new DefaultHttpClient();
	        HttpResponse httpResponse = httpClient.execute(get);
	        if (httpResponse.getStatusLine().getStatusCode() == 200) {
	            Log.d("demo", "HTTP Get succeeded");

	            HttpEntity messageEntity = httpResponse.getEntity();
	            InputStream is = messageEntity.getContent();
	            BufferedReader br = new BufferedReader(new InputStreamReader(is));
	            String line;
	            while ((line = br.readLine()) != null) {
	                response.append(line);
	            }
	        }
	    } catch (Exception e) {
	        Log.e("demo", e.getMessage());
	    }
	    Log.d("demo", "Done with HTTP getting");
	    return response.toString();
	}

	public Document getDomElement(String xml) {
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {

			DocumentBuilder db = dbf.newDocumentBuilder();

			InputSource is = new InputSource();
			is.setCharacterStream(new StringReader(xml));
			doc = (Document) db.parse(is);

		} catch (ParserConfigurationException e) {
			Log.e("Error: ", e.getMessage());
			return null;
		} catch (SAXException e) {
			Log.e("Error: ", e.getMessage());
			return null;
		} catch (IOException e) {
			Log.e("Error: ", e.getMessage());
			return null;
		}

		return doc;
	}

	public final String getElementValue(Node elem) {
		Node child;
		if (elem != null) {
			if (elem.hasChildNodes()) {
				for (child = elem.getFirstChild(); child != null; child = child
						.getNextSibling()) {
					if (child.getNodeType() == Node.TEXT_NODE
							|| (child.getNodeType() == Node.CDATA_SECTION_NODE)) {
						return child.getNodeValue();
					}
				}
			}
		}
		return "";
	}

	public String getValue(Element item, String str) {
		NodeList n = item.getElementsByTagName(str);
		return this.getElementValue(n.item(0));
	}

}

b. Retrive the parsing result: First we create a POJO class to hold the data of the videos coming after parsing the xml file.
VideoDetail.java

public class VideoDetail {

	String title;
	String video_id;
	String duration;
	String icon_url;
	
	public String getIcon_url() {
		return icon_url;
	}
	public void setIcon_url(String icon_url) {
		this.icon_url = icon_url;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getVideo_id() {
		return video_id;
	}
	public void setVideo_id(String video_id) {
		this.video_id = video_id;
	}
	public String getDuration() {
		return duration;
	}
	public void setDuration(String duration) {
		this.duration = duration;
	}
	
}

Lets us create an activity we will trigger the parsing and displays video data in ListView. This activity contains an AsycTask inner as to start a network operation we need to do it in different thread.

HomeActivity.java

package org.aynsoft.playList;

import java.util.ArrayList;
import java.util.List;

import org.aynsoft.adapter.VideoListAdapter;
import org.aynsoft.java.Parser;
import org.aynsoft.java.VideoDetail;
import org.w3c.dom.NodeList;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

public class HomeActivity extends Activity implements  OnItemClickListener{

	private ListView videoList;
	private VideoListAdapter adapter;
	private List<VideoDetail > list;
	public static final String ID_Extra="ID";
	public static final String PROCESS_DIALOG_MSG="Loading...";
	
	private static final String url="http://gdata.youtube.com/feeds/api/playlists/" +
				"PL4E272D49F6209D23"+//Your playlist ID
				"?v=2&max-results=50";//Number of max counts you want.
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);		
		list=new ArrayList<VideoDetail>();
		adapter=new VideoListAdapter(HomeActivity.this, list);		
		setContentView(R.layout.listview);
		
		
		videoList=(ListView)this.findViewById(R.id.movie_list_view);
		videoList.setAdapter(adapter);
		videoList.setOnItemClickListener(this);		

		//StartLoading
		startLoading(url);
	}	
	
	
	public void startLoading(String url){
		new LoadMoviesAsync().execute(url);
	}
	
	class LoadMoviesAsync extends AsyncTask<String,VideoDetail,Void>{
		ProgressDialog dialog;
		@Override
		protected void onPreExecute() {
			dialog=new ProgressDialog(HomeActivity.this);
			dialog.setMessage(PROCESS_DIALOG_MSG);
			dialog.show();
			super.onPreExecute();
		}		
		@Override
		protected Void doInBackground(String... params) {
			String url=params[0];			
			Parser parser=new Parser();
			NodeList movieContentLst=parser.getResponceNodeList(url);
			//Log.i("HomeActivity",""+movieContentLst.getLength());
			if(movieContentLst!=null){
				for(int i=0;i<movieContentLst.getLength();i++){
					publishProgress(parser.getResult(movieContentLst, i));
				}
			}
			
			return null;
		}
		
		@Override
		protected void onProgressUpdate(VideoDetail... values) {
			// TODO Auto-generated method stub
			super.onProgressUpdate(values);
			addItem(values);
			adapter.notifyDataSetChanged();
		}	
		public void addItem(VideoDetail... items){
			for(VideoDetail item: items){
				list.add(item);
			}	
		}
		@Override
		protected void onPostExecute(Void result) {
			if(dialog.isShowing()){
				dialog.dismiss();
			}		
			Toast.makeText(getBaseContext(), ""+list.size(),Toast.LENGTH_SHORT).show();
			super.onPostExecute(result);
		}
	}

	@Override
	public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {				
		Intent i=new Intent(HomeActivity.this,YouTubePlayerActivity.class);
		i.putExtra(ID_Extra,""+list.get(arg2).getVideo_id());
		startActivity(i);			
	}
	
}

Above is just the code snippet. You can download the full source code Here.

Related Posts

4 Comments

    excellent tutorial….

    hi…it is nice…Where can i get the full Source code….

    superb

    Excellent work…

Leave a comment

Hey, so you decided to leave a comment! That's great. Just fill in the required fields and hit submit. Note that your comment will need to be reviewed before its published.