youtube.YoutubeApiClient.java Source code

Java tutorial

Introduction

Here is the source code for youtube.YoutubeApiClient.java

Source

package youtube;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import org.joda.time.Period;
import org.joda.time.Seconds;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import api.MetalconYoutubeApi;
import api.YoutubeMetaData;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;

/**
 * 
 * @author tobi, rpickhardt
 * 
 */

public class YoutubeApiClient implements MetalconYoutubeApi {

    public Properties properties;

    public YoutubeApiClient() {
        properties = new Properties();
        try {
            properties.load(new FileInputStream("freebase.properties"));
        } catch (FileNotFoundException e) {
            System.out.println(
                    "you need a file freebase.properties. look in your git for freebase.properties.sample and rename it");
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see youtube.MetalconYoutubeApi#getVideoClipIDs(java.lang.String,
     * java.util.List, java.util.List)
     */

    public void getVideoClipIDs(String youtubeChannelName, List<YoutubeMetaData> resultContainer,
            List<YoutubeMetaData> lockedContainer) {
        String youtubeChannelId = getYoutubeChannelId(youtubeChannelName);
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/playlistItems");
        url.put("part", "snippet");
        url.put("playlistId", youtubeChannelId);
        url.put("key", properties.get("API_KEY"));
        url.put("maxResults", "50");
        JSONObject response = makeHttpRequest(url);
        System.out.println("response:  " + response);

        JSONArray responseItems = (JSONArray) response.get("items");

        for (int i = 0; i < responseItems.size(); ++i) {
            JSONObject responseItemsEntry = (JSONObject) responseItems.get(i);
            JSONObject responseItemsEntrySnippet = (JSONObject) responseItemsEntry.get("snippet");
            JSONObject responseItemsEntrySnippetResourceid = (JSONObject) responseItemsEntrySnippet
                    .get("resourceId");
            String videoID = responseItemsEntrySnippetResourceid.get("videoId").toString();
            boolean checkLockedInfo = getLockedInfo(videoID);
            YoutubeMetaData temp = new YoutubeMetaData();
            if (checkLockedInfo) {
                temp.setYoutubeID(videoID);
                JSONObject detailedResults = genericYoutubeCall("snippet, contentDetails, statistics, status",
                        videoID);
                processingDetailedResults(detailedResults, temp);
                resultContainer.add(temp);
            } else {
                temp.setYoutubeID(videoID);
                JSONObject detailedResults = genericYoutubeCall("snippet, contentDetails, statistics, status",
                        videoID);
                processingDetailedResults(detailedResults, temp);
                lockedContainer.add(temp);
            }
        }
        if (response.containsKey("nextPageToken")) {
            String nextPageToken = response.get("nextPageToken").toString();
            getNextPage(youtubeChannelId, nextPageToken, resultContainer, lockedContainer);
        }
        System.out.println("List of available Videos(" + resultContainer.size() + ")");
        System.out.println("List of locked Videos (" + lockedContainer.size() + ")");
        for (int i = 0; i < lockedContainer.size(); i++) {
            System.out.print(lockedContainer.get(i).getYoutubeID() + " ");
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see youtube.MetalconYoutubeApi#youtubeSongSearch(int, java.lang.String,
     * java.lang.String)
     */

    public List<YoutubeMetaData> youtubeSongSearch(int maxResults, String query, String topicID) {
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/search");
        url.put("part", "id");
        url.put("maxResults", maxResults);
        url.put("q", query);
        url.put("topicId", topicID);
        url.put("type", "video");
        url.put("key", properties.get("API_KEY"));
        return processingSearchResults(makeHttpRequest(url));
    }

    /*
     * (non-Javadoc)
     * 
     * @see youtube.MetalconYoutubeApi#youtubeSongSearch(int, java.lang.String)
     */

    public List<YoutubeMetaData> youtubeSongSearch(int maxResults, String query) {
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/search");
        url.put("part", "id");
        url.put("maxResults", maxResults);
        if (query.startsWith("/m/")) {
            url.put("topicId", query);
        } else {
            url.put("q", query);
        }
        url.put("type", "video");
        url.put("key", properties.get("API_KEY"));
        return processingSearchResults(makeHttpRequest(url));
    }

    /*
     * (non-Javadoc)
     * 
     * @see youtube.MetalconYoutubeApi#youtubeCall(java.lang.String,
     * java.lang.String)
     */
    public YoutubeMetaData youtubeCall(String part, String youtubeID) {
        JSONObject obj = genericYoutubeCall(part, youtubeID);
        YoutubeMetaData ymd = new YoutubeMetaData();
        ymd.setYoutubeID(youtubeID);
        return processingDetailedResults(obj, ymd);
    }

    /**
     * helper function to make an http request to youtube
     * 
     * @param url
     * @return
     */
    private JSONObject makeHttpRequest(GenericUrl url) {
        HttpTransport httpTransport = new NetHttpTransport();
        HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
        HttpRequest request;
        try {
            request = requestFactory.buildGetRequest(url);
            HttpResponse httpResponse = request.execute();
            JSONParser parser = new JSONParser();
            return (JSONObject) parser.parse(httpResponse.parseAsString());

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 
     * @param part
     *            specifies the type of Youtube call. Relevant types are:
     *            snippet, contentDetails, statistics, topicDetails
     * @param youtubeID
     *            id of the youtube clip you need more informations about
     * @return
     * @return returns a JSONObject from Youtube
     * @throws IOException
     * 
     *             This method can retrieve different kinds of informations to a
     *             youtube clip and is used to fill the YoutubeMetaData Objects
     *             "snippet" provides informations for YoutubeID, ChannelID,
     *             title, publishedAt "contentDetails" gives back the duration
     *             "statistics" returns informations about viewcount, likes,
     *             dislikes and comments "topicDetails" not used at the moment,
     *             contains other freebase ids
     * @throws ParseException
     */
    private JSONObject genericYoutubeCall(String part, String youtubeID) {
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/videos");
        url.put("part", part);
        url.put("id", youtubeID);
        url.put("key", properties.get("API_KEY"));
        return makeHttpRequest(url);
    }

    /**
     * 
     * @param videoID
     *            needs a Youtube videoID
     * @return true if the video is viewable in Germany, false if it is blocked
     *         or if the service is currently unavailable
     * @throws IOException
     * @throws ParseException
     * 
     *             This method checks if a youtube video is available to view in
     *             germany or regionLocked by GEMA
     */

    // TODO: refactor program to remove this method, can be done with a single
    // request to youtube. Requires a lot of refactoring in the
    // processingSearchResults()

    private boolean getLockedInfo(String videoID) {
        // https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id=91EAEKF2plE&key={YOUR_API_KEY}
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/videos");
        url.put("part", "contentDetails, status");
        url.put("id", videoID);
        url.put("key", properties.get("API_KEY"));
        JSONObject response = makeHttpRequest(url);
        if (response == null) {
            return false;
        }
        JSONArray responseItems = (JSONArray) response.get("items");
        JSONObject responseItemsEntry = (JSONObject) responseItems.get(0);
        JSONObject responseItemsEntryContentdetails = (JSONObject) responseItemsEntry.get("contentDetails");
        JSONObject responseItemsEntryStatus = (JSONObject) responseItemsEntry.get("status");
        Boolean responseItemsEntryStatusEmbeddable = (Boolean) responseItemsEntryStatus.get("embeddable");
        if (responseItemsEntryContentdetails.containsKey("regionRestriction")
                || responseItemsEntryStatus.get("uploadStatus").toString() == "deleted"
                || responseItemsEntryStatus.get("uploadStatus").toString() == "failed"
                || responseItemsEntryStatus.get("uploadStatus").toString() == "rejected"
                || responseItemsEntryStatus.get("privacyStatus").toString() == "private"
                || !responseItemsEntryStatusEmbeddable) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 
     * @param channelName
     *            requires a String with a Youtube Channel Name
     * @return
     * 
     *         This Method retrieves
     */

    private String getYoutubeChannelId(String channelName) {
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/channels");

        url.put("key", properties.get("API_KEY"));
        url.put("forUsername", channelName);
        url.put("part", "contentDetails");
        JSONObject response = makeHttpRequest(url);
        JSONArray responseItems = (JSONArray) response.get("items");
        JSONObject responseItemsEntry = (JSONObject) responseItems.get(0);
        JSONObject responseItemsEntryContentdetails = (JSONObject) responseItemsEntry.get("contentDetails");
        JSONObject responseItemsEntryContentdetailsRelatedplaylists = (JSONObject) responseItemsEntryContentdetails
                .get("relatedPlaylists");
        return responseItemsEntryContentdetailsRelatedplaylists.get("uploads").toString();
    }

    /**
     * 
     * @param youtubeChannelId
     *            requires a youtube channel id
     * @param nextPageToken
     *            youtube marker that is used to navigate between search pages
     * @param resultContainer
     *            List containing all videos from a channel
     * @param lockedList
     *            containing all GEMA blocked videos from a channel
     * @throws IOException
     * @throws ParseException
     * 
     *             this is a submethod to the getVideoClipIDs(String
     *             youtubeChannelId){} method to retrieve more than 50 video
     *             results
     */

    private void getNextPage(String youtubeChannelId, String nextPageToken, List<YoutubeMetaData> resultContainer,
            List<YoutubeMetaData> lockedContainer) {
        GenericUrl url = new GenericUrl("https://www.googleapis.com/youtube/v3/playlistItems");
        url.put("part", "snippet");
        url.put("playlistId", youtubeChannelId);
        url.put("key", properties.get("API_KEY"));
        url.put("maxResults", "50");
        url.put("pageToken", nextPageToken);
        JSONObject response = makeHttpRequest(url);
        JSONArray responseItems = (JSONArray) response.get("items");

        for (int i = 0; i < responseItems.size(); ++i) {
            JSONObject responseItemsEntry = (JSONObject) responseItems.get(i);
            JSONObject responseItemsEntrySnippet = (JSONObject) responseItemsEntry.get("snippet");
            JSONObject responseItemsEntrySnippetResourceid = (JSONObject) responseItemsEntrySnippet
                    .get("resourceId");
            String videoID = responseItemsEntrySnippetResourceid.get("videoId").toString();
            boolean checkRegionLock = getLockedInfo(videoID);
            YoutubeMetaData temp = new YoutubeMetaData();
            if (checkRegionLock) {
                temp.setYoutubeID(videoID);
                resultContainer.add(temp);
            } else {
                temp.setYoutubeID(videoID);
                lockedContainer.add(temp);
            }

        }
        if (response.containsKey("nextPageToken")) {
            String newNextPageToken = response.get("nextPageToken").toString();
            getNextPage(youtubeChannelId, newNextPageToken, resultContainer, lockedContainer);
        }

    }

    /**
     * 
     * @param response
     *            Input is an JSONObject produced from the method youtubeSearch
     * @return
     * @throws ParseException
     * @throws IOException
     * 
     *             This method iterates over all entries it got from the common
     *             youtube search and tries to fill all fields for the youtube
     *             objects
     * @throws java.text.ParseException
     * 
     */

    private List<YoutubeMetaData> processingSearchResults(JSONObject response) {
        if (response == null) {
            return null;
        }
        List<YoutubeMetaData> container = new ArrayList<YoutubeMetaData>();
        JSONArray responseItems = (JSONArray) response.get("items");
        System.out.println(responseItems);
        for (int i = 0; i < responseItems.size(); i++) {
            JSONObject responseItemsEntry = (JSONObject) responseItems.get(i);
            JSONObject responseItemsId = (JSONObject) responseItemsEntry.get("id");
            String youtubeId = responseItemsId.get("videoId").toString();
            if (getLockedInfo(youtubeId)) {
                YoutubeMetaData temp = new YoutubeMetaData();
                temp.setYoutubeID(youtubeId);
                System.out.println("www.youtube.com/watch?v=" + youtubeId);
                JSONObject detailedResults = genericYoutubeCall("snippet, contentDetails, statistics, status",
                        youtubeId);
                temp = processingDetailedResults(detailedResults, temp);
                if (temp == null) {
                    continue;
                }
                container.add(temp);
            } else {
                System.out.println("The video with the id: " + youtubeId + " is not available!");
            }
        }
        return container;
    }

    /**
     * 
     * @param response
     *            gets the detailed informations JSON produced eariler,
     *            containing all informations about a sinlge video
     * @param youtubeTemp
     *            is a reference to the youtube object we try to fill in the for
     *            loop
     * 
     *            the method iterates over the details JSON and fills all fields
     * @throws java.text.ParseException
     */

    private YoutubeMetaData processingDetailedResults(JSONObject response, YoutubeMetaData youtubeTemp) {
        JSONArray responseItems = (JSONArray) response.get("items");
        JSONObject responseItemsEntry = (JSONObject) responseItems.get(0);
        JSONObject responseSnippet = (JSONObject) responseItemsEntry.get("snippet");
        JSONObject responseStatus = (JSONObject) responseItemsEntry.get("status");
        System.out.println("channelId " + responseSnippet.get("channelId").toString());
        youtubeTemp.setChannelID(responseSnippet.get("channelId").toString());
        youtubeTemp.setTitle(responseSnippet.get("title").toString());
        System.out.println("title: " + responseSnippet.get("title").toString());
        String tempDate = responseSnippet.get("publishedAt").toString();
        DateFormat formatter = new SimpleDateFormat("yyyy-mm-dd'T'HH:mm:ss");
        Date date = null;
        try {
            date = formatter.parse(tempDate);
        } catch (java.text.ParseException e) {
            e.printStackTrace();
            return null;
        }
        youtubeTemp.setPublishedAt(date);
        System.out.println("publishedAt: " + youtubeTemp.getPublishedAt());
        JSONObject responseContentDetails = (JSONObject) responseItemsEntry.get("contentDetails");
        youtubeTemp.setDuration(responseContentDetails.get("duration").toString());
        PeriodFormatter pf = ISOPeriodFormat.standard();
        Period p = pf.parsePeriod(responseContentDetails.get("duration").toString());
        Seconds s = p.toStandardSeconds();
        System.out.println("durationInSecond:  " + s.getSeconds());
        youtubeTemp.setDurationInSeconds(s.getSeconds());
        System.out.println("duration " + responseContentDetails.get("duration").toString());
        JSONObject responseStatistics = (JSONObject) responseItemsEntry.get("statistics");
        youtubeTemp.setViewCount(responseStatistics.get("viewCount").toString());
        System.out.println("viewCount" + responseStatistics.get("viewCount").toString());
        youtubeTemp.setLikeCount(responseStatistics.get("likeCount").toString());
        System.out.println("likeCount" + responseStatistics.get("likeCount").toString());
        youtubeTemp.setDislikeCount(responseStatistics.get("dislikeCount").toString());
        System.out.println("dislikeCount" + responseStatistics.get("dislikeCount").toString());
        youtubeTemp.setCommentCount(responseStatistics.get("commentCount").toString());
        System.out.println("commentCount" + responseStatistics.get("commentCount").toString());
        boolean isCreativeCommon = false;
        if (responseStatus.get("license").toString() == "creativeCommon")
            isCreativeCommon = true;
        youtubeTemp.setCreativeCommon(isCreativeCommon);
        System.out.println("creativeCommon: " + youtubeTemp.isCreativeCommon());
        System.out.println("------------------------------");
        return youtubeTemp;
    }

}