com.vimeo.VimeoUploadClient.java Source code

Java tutorial

Introduction

Here is the source code for com.vimeo.VimeoUploadClient.java

Source

package com.vimeo;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.activation.MimetypesFileTypeMap;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
import org.apache.commons.net.io.Util;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.VimeoApi;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

/* 
    
 VideoUploadClient
    
 Copyright (c) 2012 Enrique Esteban at Medialab Prado
    
 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/>.
    
 */

public class VimeoUploadClient implements Runnable {

    final static String TOKEN_FILE = ".vimeo-token";
    final static String CONFIG_FILE = ".vimeo-uploader";
    final static String ENDPOINT = "http://vimeo.com/api/rest/v2";
    static boolean saveToken = true;
    static boolean verbose = true;
    static boolean checkStatusOnly = false;

    File videoFile;
    String videoTitle;
    String description;
    String keywords;

    /**
     * vimeo service - main object
     */
    private OAuthService service;
    private Token accessToken;

    String apiKey;
    String secret;

    public long currentBytesTransferred;
    public long currentStreamSize;
    private Thread vimeoThread;
    private boolean uploading = false;

    public VimeoUploadClient(String apiKey, String secret) throws IOException, APIException {

        saveToken = false; // no save token
        verbose = true; // be verbose
        checkStatusOnly = false; // we want upload

        this.apiKey = apiKey;
        this.secret = secret;

        /**
         * read .vimeo-uploader
         */

        FileInputStream in1 = null;
        Properties properties = null;
        try {
            File f = new File(System.getProperty("user.home"), VimeoUploadClient.CONFIG_FILE);
            properties = new Properties();
            if (f.createNewFile()) {
                properties.put("apiKey", apiKey);
                properties.put("secret", secret);
                properties.store(new FileOutputStream(f), "vimeo-uploader configuration file");
            }
            in1 = new FileInputStream(f);
            properties.load(in1);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            in1.close();
        }

        try {
            service = new ServiceBuilder().provider(VimeoApi.class).apiKey(properties.getProperty("apiKey"))
                    .apiSecret(properties.getProperty("secret")).build();
        } catch (Exception e) {
            System.out.println(e.getMessage() + "\nCheck Your configuration file (" + CONFIG_FILE + ")");
            return;
        }

        /**
         * try read saved token
         */
        accessToken = readToken();
        if (accessToken == null) {

            if (verbose)
                System.out.println("Fetching the Request Token...");
            Token token = service.getRequestToken();
            System.out.println("Got the Request Token!");
            System.out.println();

            if (verbose)
                System.out.println("Fetching the Authorization URL...");
            String authURL = service.getAuthorizationUrl(token);
            if (verbose)
                System.out.println("Got the Authorization URL!");
            System.out.println("Now go and authorize Scribe here:");
            System.out.println(authURL + "&permission=write");
            System.out.println("And paste the authorization code here");
            System.out.print(">>");

            // TODO: SCRIBE AUTHORIZATION GETTED THE FIRST TIME
            Verifier verifier = new Verifier("land-5zbo4");
            System.out.println();
            // Trade the Request Token and Verfier for the Access Token
            if (verbose)
                System.out.println("Trading the Request Token for an Access Token...");
            accessToken = service.getAccessToken(token, verifier);
            if (verbose)
                System.out.println("Got the Access Token!");
            if (saveToken) {
                saveToken(accessToken);
            }
            if (verbose) {
                System.out.println("(if your curious it looks like this [token, secret]: " + accessToken + " )");
                System.out.println();
            }
        }

        // get logged username
        ResponseWrapper response = call("vimeo.test.login", null);
        String username = (((Node) path(response.getResponse().getBody(), "//username", XPathConstants.NODE))
                .getTextContent());
        System.out.printf("%-30S: %s\n", "Logged", username);

        // TODO: Get User name from Vimeo: xstain1981 -> user14301672

        // get free storage space in bytes
        response = call("vimeo.videos.upload.getQuota", null);
        String free = ((Node) path(response.getResponse().getBody(), "//upload_space", XPathConstants.NODE))
                .getAttributes().getNamedItem("free").getNodeValue();
        System.out.printf("%-30S: %s MB\n", "Free Storage Space", Double.parseDouble(free) / 1024 / 1024);

        // TODO: Get free storage (new Vimeo Account has 500.MB (January 2013))

    }

    // Video upload

    public void uploadVideo(File videoFile, String videoTitle, String description, String keywords) {

        // Initialize video variables
        this.videoFile = videoFile;
        this.description = description;
        this.keywords = keywords;
        this.videoTitle = videoTitle;

        // Initialize process variables
        this.currentBytesTransferred = 0;
        this.currentStreamSize = 0;

        uploading = true;

        vimeoThread = new Thread(this, "VimeoClientThread");
        vimeoThread.start();
    }

    @SuppressWarnings("serial")
    public void run() {
        // get a upload ticket

        try {
            ResponseWrapper response = call("vimeo.videos.upload.getTicket", new HashMap<String, String>() {
                {
                    put("upload_method", "streaming");
                }
            });
            NamedNodeMap nodeMap = ((Node) path(response.getResponse().getBody(), "//ticket", XPathConstants.NODE))
                    .getAttributes();
            final String ticketId = nodeMap.getNamedItem("id").getNodeValue();
            String endpoint = nodeMap.getNamedItem("endpoint").getNodeValue();
            System.out.printf("%-30S: %s\n", "Ticket ID", ticketId);
            System.out.printf("%-30S: %s\n", "Endpoint", endpoint);

            // check ticket
            response = call("vimeo.videos.upload.checkTicket", new HashMap<String, String>() {
                {
                    put("ticket_id", ticketId);
                }
            });
            NamedNodeMap nodeMap1 = ((Node) path(response.getResponse().getBody(), "//ticket", XPathConstants.NODE))
                    .getAttributes();
            System.out.printf("%-30S: %s\n", "Ticket VALID", nodeMap1.getNamedItem("valid").getNodeValue());

            // TODO: send video
            doPut(endpoint);

            HashMap<String, String> hm = new HashMap<String, String>();
            hm.put("filename", videoFile.getName());
            hm.put("ticket_id", ticketId);

            // Complete the upload process.
            response = call("vimeo.videos.upload.complete", hm);

            NamedNodeMap nodeMap2 = ((Node) path(response.getResponse().getBody(), "//ticket", XPathConstants.NODE))
                    .getAttributes();
            final String videoId = nodeMap2.getNamedItem("video_id").getNodeValue();
            System.out.printf("%-30S: %s\n", "Video ID", videoId);

            // TODO: set title

            hm = new HashMap<String, String>();
            hm.put("video_id", videoId);
            hm.put("title", videoTitle);

            response = call("vimeo.videos.setTitle", hm);
            NamedNodeMap nodeMap3 = ((Node) path(response.getResponse().getBody(), "//rsp", XPathConstants.NODE))
                    .getAttributes();
            String stat = nodeMap3.getNamedItem("stat").getNodeValue();
            System.out.printf("%-30S: %s\n", "set Title status", stat);

            // TODO: set description

            hm = new HashMap<String, String>();
            hm.put("video_id", videoId);
            hm.put("description", description);

            response = call("vimeo.videos.setDescription", hm);
            NamedNodeMap nodeMap4 = ((Node) path(response.getResponse().getBody(), "//rsp", XPathConstants.NODE))
                    .getAttributes();
            String stat2 = nodeMap4.getNamedItem("stat").getNodeValue();
            System.out.printf("%-30S: %s\n", "set Description status", stat2);

            // TODO: set description

            hm = new HashMap<String, String>();
            hm.put("video_id", videoId);
            hm.put("tags", keywords);

            response = call("vimeo.videos.addTags", hm);
            NamedNodeMap nodeMap5 = ((Node) path(response.getResponse().getBody(), "//rsp", XPathConstants.NODE))
                    .getAttributes();
            String stat3 = nodeMap5.getNamedItem("stat").getNodeValue();
            System.out.printf("%-30S: %s\n", "set Tags status", stat3);

            // TODO: set

            System.out.printf("DONE.\n\n");
        } catch (APIException e) {
            System.out.println("Fail uploading " + videoTitle);
            e.setStackTrace(null);
        }

        uploading = false;
    }

    /**
     * call method
     * 
     * @param method
     * @param params
     * @return
     */
    private ResponseWrapper call(String method, Map<String, String> params) throws APIException {
        if (verbose)
            System.out.println("Calling method: \"" + method + "\"");
        OAuthRequest orequest = new OAuthRequest(Verb.GET, VimeoUploadClient.ENDPOINT);
        orequest.addQuerystringParameter("method", method);
        if (params != null) {
            for (Map.Entry<String, String> p : params.entrySet()) {
                orequest.addQuerystringParameter(p.getKey(), p.getValue());
            }
        }
        service.signRequest(accessToken, orequest);
        Response response = orequest.send();
        if (verbose)
            System.out.println(response.getBody());
        /*
         * NodeList nodes = (NodeList) path(response.getBody(), "//username",
         * XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++)
         * { System.out.println(nodes.item(i).getTextContent()); }
         */

        NamedNodeMap nodeMap3 = ((Node) path(response.getBody(), "//rsp", XPathConstants.NODE)).getAttributes();
        String stat = nodeMap3.getNamedItem("stat").getNodeValue();

        if (stat.equals("fail")) {
            System.out.println(" response " + response);
            throw new APIException(method, response);
        }

        return new ResponseWrapper(response, stat);
    }

    /**
     * parse xml response
     * 
     * @param content
     * @param path
     * @param returnType
     * @return
     */
    private Object path(String content, String path, QName returnType) {
        try {
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(new StringReader(content)));
            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression expr = xpath.compile(path);
            return expr.evaluate(doc, returnType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * upload file (streaming)
     * 
     * @param endpoint
     */
    private void doPut(String endpoint) {
        URL endpointUrl;
        HttpURLConnection connection;
        try {
            endpointUrl = new URL(endpoint);
            connection = (HttpURLConnection) endpointUrl.openConnection();
            connection.setRequestMethod("PUT");
            connection.setRequestProperty("Content-Length", videoFile.length() + "");
            connection.setRequestProperty("Content-Type", new MimetypesFileTypeMap().getContentType(videoFile));
            connection.setFixedLengthStreamingMode((int) videoFile.length());
            connection.setDoOutput(true);

            CopyStreamListener listener = new CopyStreamListener() {
                public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
                    // TODO: get the values to visualize it: currentStreamSize,
                    // currentBytesTransferred
                    currentStreamSize = streamSize;
                    currentBytesTransferred = totalBytesTransferred;

                    /*
                     * System.out.printf("\r%-30S: %d / %d (%d %%)", "Sent",
                     * totalBytesTransferred, streamSize, totalBytesTransferred
                     * * 100 / streamSize);
                     */
                }

                public void bytesTransferred(CopyStreamEvent event) {
                }
            };
            InputStream in = new FileInputStream(videoFile);
            OutputStream out = connection.getOutputStream();
            System.out.println("Uploading \"" + videoFile.getAbsolutePath() + "\"... ");
            long c = Util.copyStream(in, out, Util.DEFAULT_COPY_BUFFER_SIZE, videoFile.length(), listener);
            System.out.printf("\n%-30S: %d\n", "Bytes sent", c);
            in.close();
            out.close();

            // return code
            System.out.printf("\n%-30S: %d\n", "Response code", connection.getResponseCode());

            // TODO: Response code, if everything OK the code is 200

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * save token in file
     * 
     * @param token
     * @return
     */
    private boolean saveToken(Token token) {
        File f = new File(System.getProperty("user.home"), VimeoUploadClient.TOKEN_FILE);
        try {
            f.createNewFile();
            if (f.exists()) {
                if (verbose)
                    System.out.print("Saving token \"" + token + "\" to \"" + f.getAbsolutePath() + "\" ... ");
                FileWriter w = new FileWriter(f);
                BufferedWriter writer = new BufferedWriter(w);
                writer.write(token.getToken() + ";" + token.getSecret());
                writer.close();
                if (verbose)
                    System.out.println("DONE");
            }
            return true;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return false;
    }

    /**
     * read token from file
     * 
     * @return access token
     */
    private Token readToken() {
        File f = new File(System.getProperty("user.home"), VimeoUploadClient.TOKEN_FILE);
        if (f.exists()) {
            if (verbose)
                System.out.println("Reading token from \"" + f.getAbsolutePath() + "\"");
            try {
                FileReader r = new FileReader(f);
                BufferedReader br = new BufferedReader(r);
                String token1 = br.readLine();
                Token token = new Token(token1.split(";")[0], token1.split(";")[1]);
                br.close();
                return token;
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        return null;
    }

    public boolean isUploading() {
        return uploading;
    }

    public double getProgress() {
        return (double) currentBytesTransferred / (double) currentStreamSize;
    }

    public class ResponseWrapper {
        Response response;
        String status;

        public ResponseWrapper(Response response, String status) {
            this.response = response;
            this.status = status;
        }

        public String getStatus() {
            return status;
        }

        public Response getResponse() {
            return response;
        }
    }

    @SuppressWarnings("serial")
    public class APIException extends Exception {
        Response response;
        String method;

        public APIException(String method, Response response) {
            this.response = response;
            this.method = method;
        }

        @Override
        public String getMessage() {
            return method + " FAIL\nRESPONSE BODY:\n" + response.getBody();
        }
    }

}