com.gmt2001.YouTubeAPIv3.java Source code

Java tutorial

Introduction

Here is the source code for com.gmt2001.YouTubeAPIv3.java

Source

/*
 * Copyright (C) 2015 www.phantombot.net
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.gmt2001;

import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Date;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import javax.net.ssl.HttpsURLConnection;
import me.mast3rplan.phantombot.PhantomBot;
import org.apache.commons.io.IOUtils;
import org.joda.time.Period;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Communicates with YouTube via the version 3 API
 *
 * @author gmt2001
 */
public class YouTubeAPIv3 {

    private static final YouTubeAPIv3 instance = new YouTubeAPIv3();
    private String apikey = "AIzaSyCzHxG53pxE0hWrWBIMMGm75PRHBQ8ZP8c";

    private enum request_type {

        GET, POST, PUT, DELETE
    };

    public static YouTubeAPIv3 instance() {
        return instance;
    }

    private YouTubeAPIv3() {
        Thread.setDefaultUncaughtExceptionHandler(com.gmt2001.UncaughtExceptionHandler.instance());
    }

    private JSONObject GetData(request_type type, String url) {
        return GetData(type, url, "");
    }

    @SuppressWarnings({ "null", "SleepWhileInLoop", "UseSpecificCatch" })
    private JSONObject GetData(request_type type, String url, String post) {
        Date start = new Date();
        Date preconnect = start;
        Date postconnect = start;
        Date prejson = start;
        Date postjson = start;
        JSONObject j = new JSONObject("{}");
        BufferedInputStream i = null;
        String rawcontent = "";
        int available = 0;
        int responsecode = 0;
        long cl = 0;

        try {
            if (url.contains("?") && !url.contains("oembed?")) {
                url += "&utcnow=" + System.currentTimeMillis();
            } else {
                if (!url.contains("oembed?")) {
                    url += "?utcnow=" + System.currentTimeMillis();
                }
            }

            URL u = new URL(url);
            HttpsURLConnection c = (HttpsURLConnection) u.openConnection();

            c.setRequestMethod(type.name());

            c.setUseCaches(false);
            c.setDefaultUseCaches(false);
            c.setConnectTimeout(5000);
            c.setReadTimeout(5000);
            c.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.52 Safari/537.36 PhantomBotJ/2015");
            c.setRequestProperty("Content-Type", "application/json-rpc");
            c.setRequestProperty("Content-length", "0");

            if (!post.isEmpty()) {
                c.setDoOutput(true);
            }

            preconnect = new Date();
            c.connect();
            postconnect = new Date();

            if (!post.isEmpty()) {
                try (BufferedOutputStream o = new BufferedOutputStream(c.getOutputStream())) {
                    IOUtils.write(post, o);
                }
            }

            String content;
            cl = c.getContentLengthLong();
            responsecode = c.getResponseCode();

            if (c.getResponseCode() == 200) {
                i = new BufferedInputStream(c.getInputStream());
            } else {
                i = new BufferedInputStream(c.getErrorStream());
            }

            /*
             * if (i != null) { available = i.available();
             *
             * while (available == 0 && (new Date().getTime() -
             * postconnect.getTime()) < 450) { Thread.sleep(500); available =
             * i.available(); }
             *
             * if (available == 0) { i = new
             * BufferedInputStream(c.getErrorStream());
             *
             * if (i != null) { available = i.available(); } } }
             *
             * if (available == 0) { content = "{}"; } else { content =
             * IOUtils.toString(i, c.getContentEncoding()); }
             */
            content = IOUtils.toString(i, c.getContentEncoding());
            rawcontent = content;
            prejson = new Date();
            j = new JSONObject(content);
            j.put("_success", true);
            j.put("_type", type.name());
            j.put("_url", url);
            j.put("_post", post);
            j.put("_http", c.getResponseCode());
            j.put("_available", available);
            j.put("_exception", "");
            j.put("_exceptionMessage", "");
            j.put("_content", content);
            postjson = new Date();
        } catch (JSONException ex) {
            if (ex.getMessage().contains("A JSONObject text must begin with")) {
                j = new JSONObject("{}");
                j.put("_success", true);
                j.put("_type", type.name());
                j.put("_url", url);
                j.put("_post", post);
                j.put("_http", 0);
                j.put("_available", available);
                j.put("_exception", "MalformedJSONData (HTTP " + responsecode + ")");
                j.put("_exceptionMessage", "");
                j.put("_content", rawcontent);
            } else {
                com.gmt2001.Console.err.logStackTrace(ex);
            }
        } catch (NullPointerException ex) {
            com.gmt2001.Console.err.printStackTrace(ex);
        } catch (MalformedURLException ex) {
            j.put("_success", false);
            j.put("_type", type.name());
            j.put("_url", url);
            j.put("_post", post);
            j.put("_http", 0);
            j.put("_available", available);
            j.put("_exception", "MalformedURLException");
            j.put("_exceptionMessage", ex.getMessage());
            j.put("_content", "");

            if (PhantomBot.enableDebugging) {
                com.gmt2001.Console.err.printStackTrace(ex);
            } else {
                com.gmt2001.Console.err.logStackTrace(ex);
            }
        } catch (SocketTimeoutException ex) {
            j.put("_success", false);
            j.put("_type", type.name());
            j.put("_url", url);
            j.put("_post", post);
            j.put("_http", 0);
            j.put("_available", available);
            j.put("_exception", "SocketTimeoutException");
            j.put("_exceptionMessage", ex.getMessage());
            j.put("_content", "");

            if (PhantomBot.enableDebugging) {
                com.gmt2001.Console.err.printStackTrace(ex);
            } else {
                com.gmt2001.Console.err.logStackTrace(ex);
            }
        } catch (IOException ex) {
            j.put("_success", false);
            j.put("_type", type.name());
            j.put("_url", url);
            j.put("_post", post);
            j.put("_http", 0);
            j.put("_available", available);
            j.put("_exception", "IOException");
            j.put("_exceptionMessage", ex.getMessage());
            j.put("_content", "");

            if (PhantomBot.enableDebugging) {
                com.gmt2001.Console.err.printStackTrace(ex);
            } else {
                com.gmt2001.Console.err.logStackTrace(ex);
            }
        } catch (Exception ex) {
            j.put("_success", false);
            j.put("_type", type.name());
            j.put("_url", url);
            j.put("_post", post);
            j.put("_http", 0);
            j.put("_available", available);
            j.put("_exception", "Exception [" + ex.getClass().getName() + "]");
            j.put("_exceptionMessage", ex.getMessage());
            j.put("_content", "");

            if (PhantomBot.enableDebugging) {
                com.gmt2001.Console.err.printStackTrace(ex);
            } else {
                com.gmt2001.Console.err.logStackTrace(ex);
            }
        }

        if (i != null) {
            try {
                i.close();
            } catch (IOException ex) {
                j.put("_success", false);
                j.put("_type", type.name());
                j.put("_url", url);
                j.put("_post", post);
                j.put("_http", 0);
                j.put("_available", available);
                j.put("_exception", "IOException");
                j.put("_exceptionMessage", ex.getMessage());
                j.put("_content", "");

                if (PhantomBot.enableDebugging) {
                    com.gmt2001.Console.err.printStackTrace(ex);
                } else {
                    com.gmt2001.Console.err.logStackTrace(ex);
                }
            }
        }

        if (PhantomBot.enableDebugging) {
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetData Timers "
                    + (preconnect.getTime() - start.getTime()) + " " + (postconnect.getTime() - start.getTime())
                    + " " + (prejson.getTime() - start.getTime()) + " " + (postjson.getTime() - start.getTime())
                    + " " + start.toString() + " " + postjson.toString());
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetData Exception " + j.getString("_exception")
                    + " " + j.getString("_exceptionMessage"));
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetData HTTP/Available " + j.getInt("_http")
                    + "(" + responsecode + ")/" + j.getInt("_available") + "(" + cl + ")");
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetData RawContent[0,100] "
                    + j.getString("_content").substring(0, Math.min(100, j.getString("_content").length())));
        }

        return j;
    }

    public void SetAPIKey(String apikey) {
        this.apikey = apikey;
    }

    public String[] SearchForVideo(String q) {
        if (PhantomBot.enableDebugging) {
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo Start q=" + q);
        }

        if (q.contains("v=") | q.contains("?v=")) {
            q = q.substring(q.indexOf("v=") + 2, q.indexOf("v=") + 13);
        }
        Pattern pattern = Pattern
                .compile(".*(?:youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=)([^#\\&\\?^\\s]*).*");
        Matcher matcher = pattern.matcher(q);

        if (matcher.matches()) {
            q = matcher.group(1);
        }

        JSONObject j = GetData(request_type.GET,
                "https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=" + q + "&format=json");
        if (j.getBoolean("_success") && !j.toString().contains("Bad Request")
                && !j.toString().contains("Not Found")) {
            if (j.toString().contains("Unauthorized")) {
                if (PhantomBot.enableDebugging) {
                    com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Private");
                }

                return new String[] { q, "Video Marked Private", "" };
            }
            if (j.getInt("_http") == 200) {
                try {
                    if (PhantomBot.enableDebugging) {
                        com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Success");
                    }

                    String a = j.getString("title");
                    return new String[] { q, a, "" };
                } catch (Exception e) {
                    if (PhantomBot.enableDebugging) {
                        com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo Exception");
                    }

                    return new String[] { "", "", "" };
                }
            }
        } else {
            q = q.replaceAll("[^a-zA-Z0-9 ]", "");
            q = q.replace(" ", "%20");

            JSONObject j2 = GetData(request_type.GET, "https://www.googleapis.com/youtube/v3/search?q=" + q
                    + "&key=" + apikey + "&type=video&part=snippet&maxResults=1");
            if (j2.getBoolean("_success")) {
                if (j2.getInt("_http") == 200) {
                    JSONObject pageInfo = j2.getJSONObject("pageInfo");
                    if (pageInfo.getInt("totalResults") == 0) {
                        if (PhantomBot.enableDebugging) {
                            com.gmt2001.Console.out
                                    .println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End No Results");
                        }

                        return new String[] { q, "No Search Results Found", "" };
                    }

                    JSONArray a = j2.getJSONArray("items");
                    if (a.length() > 0) {
                        JSONObject it = a.getJSONObject(0);

                        JSONObject id = it.getJSONObject("id");
                        JSONObject sn = it.getJSONObject("snippet");

                        if (PhantomBot.enableDebugging) {
                            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Success2");
                        }

                        return new String[] { id.getString("videoId"), sn.getString("title"),
                                sn.getString("channelTitle") };
                    } else {
                        if (PhantomBot.enableDebugging) {
                            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Fail");
                        }

                        return new String[] { "", "", "" };
                    }
                } else {
                    if (PhantomBot.enableDebugging) {
                        com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Fail2");
                    }

                    return new String[] { "", "", "" };
                }
            } else {
                if (PhantomBot.enableDebugging) {
                    com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Fail3");
                }

                return new String[] { "", "", "" };
            }
        }

        if (PhantomBot.enableDebugging) {
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.SearchForVideo End Fail4");
        }

        return new String[] { "", "", "" };
    }

    public int[] GetVideoLength(String id) {
        if (PhantomBot.enableDebugging) {
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetVideoLength Start id=" + id);
        }

        JSONObject j = GetData(request_type.GET, "https://www.googleapis.com/youtube/v3/videos?id=" + id + "&key="
                + apikey + "&part=contentDetails");
        if (j.getBoolean("_success")) {
            if (j.getInt("_http") == 200) {
                JSONArray a = j.getJSONArray("items");
                if (a.length() > 0) {
                    JSONObject i = a.getJSONObject(0);

                    JSONObject cd = i.getJSONObject("contentDetails");

                    PeriodFormatter formatter = ISOPeriodFormat.standard();

                    Period d = formatter.parsePeriod(cd.getString("duration"));

                    //String d = cd.getString("duration").substring(2);
                    int h, m, s;

                    String hours = d.toStandardHours().toString().substring(2);
                    h = Integer.parseInt(hours.substring(0, hours.indexOf("H")));

                    String minutes = d.toStandardMinutes().toString().substring(2);
                    m = Integer.parseInt(minutes.substring(0, minutes.indexOf("M")));

                    String seconds = d.toStandardSeconds().toString().substring(2);
                    s = Integer.parseInt(seconds.substring(0, seconds.indexOf("S")));

                    /*
                     * if (d.contains("H")) { h =
                     * Integer.parseInt(d.substring(0, d.indexOf("H")));
                     *
                     * d = d.substring(0, d.indexOf("H")); }
                     *
                     * if (d.contains("M")) { m =
                     * Integer.parseInt(d.substring(0, d.indexOf("M")));
                     *
                     * d = d.substring(0, d.indexOf("M")); }
                     *
                     * s = Integer.parseInt(d.substring(0, d.indexOf("S")));
                     */
                    if (PhantomBot.enableDebugging) {
                        com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetVideoLength Success");
                    }

                    return new int[] { h, m, s };
                } else {
                    if (PhantomBot.enableDebugging) {
                        com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetVideoLength Fail");
                    }

                    return new int[] { 0, 0, 0 };
                }
            } else {
                if (PhantomBot.enableDebugging) {
                    com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetVideoLength Fail2");
                }

                return new int[] { 0, 0, 0 };
            }
        }

        if (PhantomBot.enableDebugging) {
            com.gmt2001.Console.out.println(">>>[DEBUG] YouTubeAPIv3.GetVideoLength Fail3");
        }

        return new int[] { 0, 0, 0 };
    }
}