org.couchpotato.CouchPotato.java Source code

Java tutorial

Introduction

Here is the source code for org.couchpotato.CouchPotato.java

Source

/*
 *    libCouchPotato is a java library for communication with couchpotato
 *    Copyright (C) 2012  David Stocking dmstocking@gmail.com
 * 
 *    http://code.google.com/p/couch-tatertot/
 *    
 *    libCouchPotato 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 org.couchpotato;

import com.google.gson.GsonBuilder;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.couchpotato.json.*;
import org.couchpotato.json.deserializer.JsonBooleanDeserializer;
import org.couchpotato.json.type.JsonBoolean;
import org.couchpotato.net.CouchAuthenticator;
import org.couchpotato.net.ssl.DefaultTrustManager;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.*;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

public class CouchPotato {

    private static final int SOCKET_TIMEOUT = 30000;

    public enum LoggingTypeEnum {
        ALL, ERROR, INFO, DEBUG;

        @Override
        public String toString() {
            return super.toString().toLowerCase();
        }
    }

    public enum PageEnum {
        ALL, WANTED, MANAGE;

        @Override
        public String toString() {
            return super.toString().toLowerCase();
        }
    }

    private String scheme;
    private String hostName;
    private int port;
    private String path;
    private String api;

    private String username;
    private String password;

    private String version;
    private boolean trustAll = true;

    public CouchPotato(boolean ssl, String host, int port, String path, String api, String username,
            String password, boolean trustAll, String trustMe) {
        this(ssl ? "https" : "http", host, port, path, api, username, password, trustAll, trustMe);
    }

    private CouchPotato(String scheme, String hostname, int port, String path, String api, String username,
            String password, boolean trustAll, String trustMe) {
        this.scheme = scheme;
        this.hostName = hostname;
        this.port = port;
        this.path = path;
        this.api = api;
        this.username = username;
        this.password = password;
        this.trustAll = trustAll;

        if (this.username == null)
            this.username = "";
        if (this.password == null)
            this.password = "";

        // Configure SSL behavior based on user preferences
        Authenticator.setDefault(new CouchAuthenticator(username, password, hostname));
        HostnameVerifier verifier;
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager(trustAll, trustMe) },
                    new SecureRandom());
            if (trustAll) {
                verifier = new AllowAllHostnameVerifier();
            } else {
                verifier = new StrictHostnameVerifier();
            }
            HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(verifier);
        } catch (NoSuchAlgorithmException e) {

        } catch (KeyManagementException e) {

        } catch (KeyStoreException e) {

        }
    }

    public String getVersion() {
        if (version == null) {
            ; // TODO go get it
        }
        return version;
    }

    public boolean appAvailable() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.commandSuccessful("app.available/", "", Object.class);
    }

    public boolean appRestart() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.commandSuccessful("app.restart/", "", Object.class);
    }

    public boolean appShutdown() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.commandSuccessful("app.shutdown/", "", Object.class);
    }

    public String appVersion() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.<AppVersionJson>command("app.version/", "", AppVersionJson.class).version;
    }

    public URL fileCache(String filename) throws MalformedURLException {
        // WOW this sucks i hope this works for both windows and linux
        try {
            filename = filename.replace("\\", "/");
            if (filename.startsWith("/") == false) {
                filename = "/" + filename;
            }
            return this.getUri("file.cache" + filename, null).toURL();
        } catch (URISyntaxException e) {
            throw new MalformedURLException(e.getMessage());
        }
    }

    public void loggingGet(int which) throws MalformedURLException, IOException, SocketTimeoutException {
        // TODO make me
    }

    public List<String> loggingPartial(Integer lines, LoggingTypeEnum type)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        if (lines != null) {
            builder.append("&lines=");
            builder.append(lines);
        }
        if (type != null) {
            builder.append("&type=");
            builder.append(type.toString().toLowerCase());
        }
        LoggingJson json = this.<LoggingJson>command("logging.partial/", builder.toString(), LoggingJson.class);
        // split will remove the time stamp ... and I want it
        //      Pattern newLine = Pattern.compile("\\\\n\\d{2}\\-\\d{2} \\d{2}:\\d{2}:\\d{2}");
        // Lazy >.> figure this out better later
        Pattern newLine = Pattern.compile("\\\\n");
        return Arrays.asList(newLine.split(json.log));
    }

    public void movieAdd(Integer profileId, String imdbId, String title)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        if (profileId != null) {
            builder.append("&profile_id=");
            builder.append(profileId);
        }
        builder.append("&identifier=");
        builder.append(imdbId);
        if (title != null) {
            builder.append("&title=");
            builder.append(title);
        }
        // all you get back is success and currently it doens't actually mean success
        // if you give an id that doesn't exist it returns "success" : true
        this.<Object>command("movie.add/", builder.toString(), Object.class);
    }

    public void movieDelete(List<Integer> IDs, PageEnum page)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        Iterator<Integer> iter = IDs.iterator();
        if (iter.hasNext()) {
            builder.append(iter.next().toString().toLowerCase());
            while (iter.hasNext()) {
                builder.append(",");
                builder.append(iter.next().toString().toLowerCase());
            }
        }
        builder.append("&delete_from=");
        builder.append(page.toString().toLowerCase());
        // SEE movieAdd for why this is here
        this.<Object>command("movie.delete/", builder.toString(), Object.class);
    }

    public void movieEdit(int profileId, int id, String defaultTitle)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&profile_id=");
        builder.append(profileId);
        builder.append("&id=");
        builder.append(id);
        builder.append("&default_title=");
        builder.append(defaultTitle);
        // SEE movieAdd for why this is here
        this.<Object>command("movie.edit/", builder.toString(), Object.class);
    }

    public MovieJson movieGet(int id) throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        builder.append(id);
        // SEE movieAdd for why this is here
        return this.<MovieWrapperJson>command("movie.get/", builder.toString(), MovieWrapperJson.class).movie;
    }

    /**
     * Gets a list of movies
     * 
     * @param status      Filter by status
     * @param limit         Number of items to return
     * @param offset      Offset to start return items at
     * @param search      Filter by search
     * @param startsWith   Filter by what the movie title starts with
     */
    public List<MovieJson> movieList(String status, int limit, int offset, String search, String startsWith)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        if (status != null) {
            builder.append("&status=");
            builder.append(status);
        }
        if (limit > 0) {
            builder.append("&limit_offset=");
            builder.append(limit);
            if (offset > 0) {
                builder.append(",");
                builder.append(offset);
            }
        }
        if (search != null) {
            builder.append("&search=");
            builder.append(search);
        }
        if (startsWith != null) {
            builder.append("&starts_with=");
            builder.append(startsWith);
        }
        return this.<MovieListJson>command("movie.list/", builder.toString(), MovieListJson.class).movies;
    }

    public void movieRefresh(int id) throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        builder.append(id);
        // SEE movieAdd for why this is here
        this.<Object>command("movie.refresh/", builder.toString(), Object.class);
    }

    public SearchResultsJson movieSearch(String query)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&q=");
        builder.append(query);
        return this.<SearchResultsJson>command("movie.search/", builder.toString(), SearchResultsJson.class);
    }

    /**
     * Gets a list of notifications
     * 
     * @param limitOffset   Filter by limit with offset
     */
    public List<NotificationJson> notificationList(String limitOffset)
            throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        if (limitOffset != null) {
            builder.append("&limit_offset=");
            builder.append(limitOffset);
        }
        return this.<NotificationListJson>command("notification.list/", builder.toString(),
                NotificationListJson.class).notifications;
    }

    public List<ProfileJson> profileList() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.<ProfileListJson>command("profile.list/", null, ProfileListJson.class).list;
    }

    public List<QualityJson> qualityList() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.<QualityListJson>command("quality.list/", null, QualityListJson.class).list;
    }

    public void releaseDelete(int id) throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        builder.append(id);
        this.<Object>command("release.delete/", builder.toString(), Object.class);
        return;
    }

    public void releaseDownload(int id) throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        builder.append(id);
        this.<Object>command("release.download/", builder.toString(), Object.class);
        return;
    }

    public void releaseIgnore(int id) throws MalformedURLException, IOException, SocketTimeoutException {
        StringBuilder builder = new StringBuilder();
        builder.append("&id=");
        builder.append(id);
        this.<Object>command("release.ignore/", builder.toString(), Object.class);
        return;
    }

    public void renamerScan() throws MalformedURLException, IOException, SocketTimeoutException {
        ;
    }

    public List<StatusJson> statusList() throws MalformedURLException, IOException, SocketTimeoutException {
        return this.<StatusListJson>command("status.list/", null, StatusListJson.class).list;
    }

    public void updaterCheck() throws MalformedURLException, IOException, SocketTimeoutException {
        ;
    }

    private URI getUri(String command, String arguments) throws URISyntaxException {
        // TODO fix this because couch potato api doesn't use all query options
        if (arguments != null && arguments.length() == 0)
            arguments = null;
        if (path == null || path.length() == 0)
            return new URI(scheme, null, hostName, port, "/api/" + api + "/" + command, arguments, null);
        else
            return new URI(scheme, null, hostName, port, "/" + path + "/api/" + api + "/" + command, arguments,
                    null);
    }

    // Using JsonResponse will not work all the time now
    // Remove it and push all the changes to the classes
    private <T> T command(String command, String arguments, Type type)
            throws MalformedURLException, IOException, SocketTimeoutException {
        try {
            URI uri = this.getUri(command, arguments);
            // this WILL throw a EOFexception if it gets a HTTP 301 response because it wont follow it
            // so ALL URLS MUST BE PERFECT!!!!
            HttpURLConnection server = (HttpURLConnection) uri.toURL().openConnection();
            // TODO going to try and not use this and see if everything works out
            //         if ( uri.getScheme().compareTo("https") == 0 ) {
            //            server = (HttpsURLConnection)uri.toURL().openConnection();
            //         } else {
            //            server = (HttpURLConnection)uri.toURL().openConnection();
            //         }
            server.setConnectTimeout(SOCKET_TIMEOUT);
            Reader reader = new BufferedReader(new InputStreamReader(server.getInputStream()));
            // TypeToken cannot figure out T so instead it must be supplied
            GsonBuilder build = new GsonBuilder();
            build.registerTypeAdapter(JsonBoolean.class, new JsonBooleanDeserializer());
            T response;
            if (type == MovieListJson.class) {
                response = (T) build.create().fromJson(reader, _NewAPI_MovieListJson.class).toOld();
            } else {
                response = build.create().fromJson(reader, type);
            }
            return response;
        } catch (URISyntaxException e) {
            throw new MalformedURLException(e.getMessage());
        }
    }

    private boolean commandSuccessful(String command, String arguments, Type type)
            throws MalformedURLException, IOException, SocketTimeoutException {
        return command(command, arguments, type) != null ? true : false;
    }

    // pointless because no JsonResponse
    //   private <T> T commandData( String command, String arguments, Type type ) throws MalformedURLException, IOException, SocketTimeoutException
    //   {
    //      return this.<T>command(command, arguments, type).data;
    //   }
}