org.drftpd.commands.tvmaze.TvMazeUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.drftpd.commands.tvmaze.TvMazeUtils.java

Source

/*
 * This file is part of DrFTPD, Distributed FTP Daemon.
 *
 * DrFTPD 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 2 of the License, or
 * (at your option) any later version.
 *
 * DrFTPD 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 DrFTPD; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.drftpd.commands.tvmaze;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.drftpd.GlobalContext;
import org.drftpd.commands.tvmaze.event.TvMazeEvent;
import org.drftpd.commands.tvmaze.metadata.TvEpisode;
import org.drftpd.commands.tvmaze.metadata.TvMazeInfo;
import org.drftpd.commands.tvmaze.vfs.TvMazeVFSData;
import org.drftpd.dynamicdata.KeyNotFoundException;
import org.drftpd.exceptions.NoAvailableSlaveException;
import org.drftpd.exceptions.SlaveUnavailableException;
import org.drftpd.plugins.sitebot.SiteBot;
import org.drftpd.sections.SectionInterface;
import org.drftpd.usermanager.User;
import org.drftpd.util.HttpUtils;
import org.drftpd.vfs.DirectoryHandle;
import org.drftpd.vfs.VirtualFileSystem;
import org.drftpd.vfs.index.AdvancedSearchParams;
import org.drftpd.vfs.index.IndexEngineInterface;
import org.drftpd.vfs.index.IndexException;
import org.drftpd.vfs.index.lucene.extensions.tvmaze.TvMazeQueryParams;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
import org.tanesha.replacer.ReplacerEnvironment;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author scitz0
 */
public class TvMazeUtils {
    private static final Logger logger = Logger.getLogger(TvMazeUtils.class);

    private static final String[] _seperators = { ".", "-", "_" };

    public static ReplacerEnvironment getShowEnv(TvMazeInfo tvShow) {
        ReplacerEnvironment env = new ReplacerEnvironment(SiteBot.GLOBAL_ENV);
        DateTimeFormatter df = DateTimeFormat.forPattern(TvMazeConfig.getInstance().getDateFormat());
        DateTimeFormatter tf = DateTimeFormat.forPattern(TvMazeConfig.getInstance().getTimeFormat());

        env.add("id", tvShow.getID());
        env.add("url", tvShow.getURL());
        env.add("name", tvShow.getName());
        env.add("type", tvShow.getType());
        env.add("language", tvShow.getLanguage());
        env.add("genres", StringUtils.join(tvShow.getGenres(), " | "));
        env.add("status", tvShow.getStatus());
        env.add("runtime", tvShow.getRuntime());
        DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd");
        env.add("premiered", df.withZone(TvMazeConfig.getInstance().getTimezone())
                .print(dtf.parseDateTime(tvShow.getPremiered())));
        env.add("network", tvShow.getNetwork());
        env.add("country", tvShow.getCountry());
        env.add("summary", StringUtils.abbreviate(tvShow.getSummary(), 250));

        if (tvShow.getPreviousEP() != null) {
            env.add("prevepid", tvShow.getPreviousEP().getID());
            env.add("prevepurl", tvShow.getPreviousEP().getURL());
            env.add("prevepname", tvShow.getPreviousEP().getName());
            env.add("prevepseason", tvShow.getPreviousEP().getSeason());
            env.add("prevepnumber", String.format("%02d", tvShow.getPreviousEP().getNumber()));
            env.add("prevepairdate", df.withZone(TvMazeConfig.getInstance().getTimezone())
                    .print(new DateTime(tvShow.getPreviousEP().getAirDate())));
            env.add("prevepairtime", tf.withZone(TvMazeConfig.getInstance().getTimezone())
                    .print(new DateTime(tvShow.getPreviousEP().getAirDate())));
            env.add("prevepruntime", tvShow.getPreviousEP().getRuntime());
            env.add("prevepsummary", StringUtils.abbreviate(tvShow.getPreviousEP().getSummary(), 250));
            env.add("prevepage", calculateAge(new DateTime(tvShow.getPreviousEP().getAirDate())));
        }
        if (tvShow.getNextEP() != null) {
            env.add("nextepid", tvShow.getNextEP().getID());
            env.add("nextepurl", tvShow.getNextEP().getURL());
            env.add("nextepname", tvShow.getNextEP().getName());
            env.add("nextepseason", tvShow.getNextEP().getSeason());
            env.add("nextepnumber", String.format("%02d", tvShow.getNextEP().getNumber()));
            env.add("nextepairdate", df.withZone(TvMazeConfig.getInstance().getTimezone())
                    .print(new DateTime(tvShow.getNextEP().getAirDate())));
            env.add("nextepairtime", tf.withZone(TvMazeConfig.getInstance().getTimezone())
                    .print(new DateTime(tvShow.getNextEP().getAirDate())));
            env.add("nextepruntime", tvShow.getNextEP().getRuntime());
            env.add("nextepsummary", StringUtils.abbreviate(tvShow.getNextEP().getSummary(), 250));
            env.add("nextepage", calculateAge(new DateTime(tvShow.getNextEP().getAirDate())));
        }

        return env;
    }

    public static ReplacerEnvironment getEPEnv(TvMazeInfo tvShow, TvEpisode tvEP) {
        ReplacerEnvironment env = new ReplacerEnvironment(SiteBot.GLOBAL_ENV);
        DateTimeFormatter df = DateTimeFormat.forPattern(TvMazeConfig.getInstance().getDateFormat());
        DateTimeFormatter tf = DateTimeFormat.forPattern(TvMazeConfig.getInstance().getTimeFormat());

        env.add("id", tvShow.getID());
        env.add("url", tvShow.getURL());
        env.add("name", tvShow.getName());
        env.add("type", tvShow.getType());
        env.add("language", tvShow.getLanguage());
        env.add("genres", StringUtils.join(tvShow.getGenres(), " | "));
        env.add("status", tvShow.getStatus());
        env.add("runtime", tvShow.getRuntime());
        DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd");
        env.add("premiered", df.withZone(TvMazeConfig.getInstance().getTimezone())
                .print(dtf.parseDateTime(tvShow.getPremiered())));
        env.add("network", tvShow.getNetwork());
        env.add("country", tvShow.getCountry());
        env.add("summary", StringUtils.abbreviate(tvShow.getSummary(), 250));

        env.add("epid", tvEP.getID());
        env.add("epurl", tvEP.getURL());
        env.add("epname", tvEP.getName());
        env.add("epseason", tvEP.getSeason());
        env.add("epnumber", String.format("%02d", tvEP.getNumber()));
        env.add("epairdate",
                df.withZone(TvMazeConfig.getInstance().getTimezone()).print(new DateTime(tvEP.getAirDate())));
        env.add("epairtime",
                tf.withZone(TvMazeConfig.getInstance().getTimezone()).print(new DateTime(tvEP.getAirDate())));
        env.add("epruntime", tvEP.getRuntime());
        env.add("epsummary", StringUtils.abbreviate(tvEP.getSummary(), 250));
        env.add("epage", calculateAge(new DateTime(tvEP.getAirDate())));

        return env;
    }

    public static TvMazeInfo createTvMazeInfo(JsonObject jObj) throws Exception {
        TvMazeInfo tvmazeInfo = new TvMazeInfo();

        tvmazeInfo.setID(jObj.get("id").getAsInt());
        tvmazeInfo.setURL(jObj.get("url").getAsString());
        tvmazeInfo.setName(jObj.get("name").getAsString());
        tvmazeInfo.setType(jObj.get("type").getAsString());
        tvmazeInfo.setLanguage(jObj.get("language").getAsString());
        tvmazeInfo
                .setGenres((String[]) new Gson().fromJson(jObj.getAsJsonArray("genres"), new TypeToken<String[]>() {
                }.getType()));
        tvmazeInfo.setStatus(jObj.get("status").getAsString());
        tvmazeInfo.setRuntime(jObj.get("runtime").getAsInt());
        tvmazeInfo.setPremiered(jObj.get("premiered").getAsString());
        JsonObject networkJsonObj = null;
        if (jObj.get("network").isJsonObject()) {
            networkJsonObj = jObj.getAsJsonObject("network");
        } else if (jObj.get("webChannel").isJsonObject()) {
            networkJsonObj = jObj.getAsJsonObject("webChannel");
        }
        if (networkJsonObj != null) {
            tvmazeInfo.setNetwork(networkJsonObj.get("name").getAsString());
            JsonObject countryJsonObj = networkJsonObj.getAsJsonObject("country");
            tvmazeInfo.setCountry(countryJsonObj.get("name").getAsString());
        }
        tvmazeInfo.setSummary(HttpUtils.htmlToString(jObj.get("summary").getAsString()));
        JsonObject linksObj = jObj.getAsJsonObject("_links");
        if (linksObj != null) {
            JsonObject prevEPObj = linksObj.getAsJsonObject("previousepisode");
            if (prevEPObj != null) {
                // Fetch and parse EP
                String epURL = prevEPObj.get("href").getAsString();
                tvmazeInfo.setPreviousEP(createTvEpisode(fetchEpisodeData(epURL)));
            }
            JsonObject nextEPObj = linksObj.getAsJsonObject("nextepisode");
            if (nextEPObj != null) {
                // Fetch and parse EP
                String epURL = nextEPObj.get("href").getAsString();
                tvmazeInfo.setNextEP(createTvEpisode(fetchEpisodeData(epURL)));
            }
        }

        return tvmazeInfo;
    }

    public static TvMazeInfo createTvMazeInfo(JsonObject jObj, int season, int number) throws Exception {
        TvMazeInfo tvmazeInfo = createTvMazeInfo(jObj);
        ArrayList<TvEpisode> epList = new ArrayList<TvEpisode>();
        JsonObject embeddedObj = jObj.getAsJsonObject("_embedded");
        if (embeddedObj != null) {
            // Add all episodes to a map with sXXeYY as key
            HashMap<String, TvEpisode> episodes = parseEpisodes(embeddedObj);
            if (number >= 0) {
                // Find the single show wanted and add to _epList
                epList.add(episodes.get("s" + season + "e" + number));
            } else if (season >= 0) {
                // All episodes of specified season wanted
                for (TvEpisode ep : episodes.values()) {
                    if (ep.getSeason() == season) {
                        epList.add(ep);
                    }
                }
            }
        }
        tvmazeInfo.setEPList(epList.toArray(new TvEpisode[epList.size()]));

        return tvmazeInfo;
    }

    private static HashMap<String, TvEpisode> parseEpisodes(JsonObject embeddedObj) throws Exception {
        HashMap<String, TvEpisode> episodes = new HashMap<String, TvEpisode>();
        ArrayList<JsonElement> episodesElement = new Gson().fromJson(embeddedObj.getAsJsonArray("episodes"),
                new TypeToken<ArrayList<JsonElement>>() {
                }.getType());
        for (JsonElement episode : episodesElement) {
            TvEpisode ep = createTvEpisode(episode.getAsJsonObject());
            episodes.put("s" + ep.getSeason() + "e" + ep.getNumber(), ep);
        }
        return episodes;
    }

    private static JsonObject fetchEpisodeData(String epURL) throws Exception {
        String data = HttpUtils.retrieveHttpAsString(epURL);
        JsonParser jp = new JsonParser();
        JsonElement root = jp.parse(data);
        return root.getAsJsonObject();
    }

    public static TvEpisode createTvEpisode(JsonObject jobj) throws Exception {
        TvEpisode tvEP = new TvEpisode();
        tvEP.setID(jobj.get("id").getAsInt());
        tvEP.setURL(jobj.get("url").getAsString());
        tvEP.setName(jobj.get("name").getAsString());
        tvEP.setSeason(jobj.get("season").getAsInt());
        tvEP.setNumber(jobj.get("number").getAsInt());
        tvEP.setAirDate(jobj.get("airstamp").getAsString());
        tvEP.setRuntime(jobj.get("runtime").getAsInt());
        tvEP.setSummary(HttpUtils.htmlToString(jobj.get("summary").getAsString()));
        return tvEP;
    }

    private static String calculateAge(DateTime epDate) {

        Period period;
        if (epDate.isBefore(new DateTime())) {
            period = new Period(epDate, new DateTime());
        } else {
            period = new Period(new DateTime(), epDate);
        }

        PeriodFormatter formatter = new PeriodFormatterBuilder().appendYears().appendSuffix("y").appendMonths()
                .appendSuffix("m").appendWeeks().appendSuffix("w").appendDays().appendSuffix("d ").appendHours()
                .appendSuffix("h").appendMinutes().appendSuffix("m").printZeroNever().toFormatter();

        return formatter.print(period);
    }

    public static String filterTitle(String title) {
        String newTitle = title.toLowerCase();
        //remove filtered words
        for (String filter : TvMazeConfig.getInstance().getFilters()) {
            newTitle = newTitle.replaceAll("\\b" + filter.toLowerCase() + "\\b", "");
        }
        //remove seperators
        for (String separator : _seperators) {
            newTitle = newTitle.replaceAll("\\" + separator, " ");
        }
        newTitle = newTitle.trim();
        //remove extra spaces
        newTitle = newTitle.replaceAll("\\s+", "%20");
        return newTitle;
    }

    public static ArrayList<DirectoryHandle> findReleases(DirectoryHandle sectionDir, User user, String showName,
            int season, int number) throws FileNotFoundException {
        IndexEngineInterface ie = GlobalContext.getGlobalContext().getIndexEngine();
        Map<String, String> inodes;

        AdvancedSearchParams params = new AdvancedSearchParams();

        TvMazeQueryParams queryParams;
        try {
            queryParams = params.getExtensionData(TvMazeQueryParams.TvMazeQUERYPARAMS);
        } catch (KeyNotFoundException e) {
            queryParams = new TvMazeQueryParams();
            params.addExtensionData(TvMazeQueryParams.TvMazeQUERYPARAMS, queryParams);
        }
        queryParams.setName(showName);
        queryParams.setSeason(season);
        queryParams.setNumber(number);

        params.setInodeType(AdvancedSearchParams.InodeType.DIRECTORY);
        params.setSortField("lastmodified");
        params.setSortOrder(true);

        try {
            inodes = ie.advancedFind(sectionDir, params);
        } catch (IndexException e) {
            throw new FileNotFoundException("Index Exception: " + e.getMessage());
        }

        ArrayList<DirectoryHandle> releases = new ArrayList<DirectoryHandle>();

        for (Map.Entry<String, String> item : inodes.entrySet()) {
            try {
                DirectoryHandle inode = new DirectoryHandle(VirtualFileSystem.fixPath(item.getKey()));
                if (!inode.isHidden(user)) {
                    releases.add(inode);
                }
            } catch (FileNotFoundException e) {
                // This is ok, could be multiple nukes fired and
                // that is has not yet been reflected in index due to async event.
            }
        }

        return releases;
    }

    public static long randomNumber() {
        return (TvMazeConfig.getInstance().getStartDelay() + (new Random())
                .nextInt(TvMazeConfig.getInstance().getEndDelay() - TvMazeConfig.getInstance().getStartDelay()))
                * 1000;
    }

    public static TvMazeInfo getTvMazeInfo(DirectoryHandle dir) {
        TvMazeVFSData tvmazeData = new TvMazeVFSData(dir);
        try {
            return tvmazeData.getTvMazeInfo();
        } catch (FileNotFoundException e) {
            // Thats strange...
            logger.error("", e);
        } catch (IOException e) {
            // To bad...
            logger.error("", e);
        } catch (NoAvailableSlaveException e) {
            // Not much to do...
        } catch (SlaveUnavailableException e) {
            // Not much to do...
        }
        return null;
    }

    public static void publishEvent(TvMazeInfo tvmazeInfo, DirectoryHandle dir, SectionInterface section) {
        if (tvmazeInfo != null) {
            // TvMaze show found, announce to IRC
            ReplacerEnvironment env;
            if (tvmazeInfo.getEPList().length == 1) {
                env = getEPEnv(tvmazeInfo, tvmazeInfo.getEPList()[0]);
            } else {
                env = getShowEnv(tvmazeInfo);
            }
            env.add("release", dir.getName());
            env.add("section", section.getName());
            env.add("sectioncolor", GlobalContext.getGlobalContext().getSectionManager().lookup(dir).getColor());
            GlobalContext.getEventService().publishAsync(new TvMazeEvent(env, dir));
        }
    }

    public static boolean isRelease(String dirName) {
        Pattern p = Pattern.compile("(\\w+\\.){3,}\\w+-\\w+");
        Matcher m = p.matcher(dirName);
        return m.find();
    }

    public static Comparator<TvEpisode> epNumberComparator = new Comparator<TvEpisode>() {
        public int compare(TvEpisode tvEpisode1, TvEpisode tvEpisode2) {
            return tvEpisode1.getNumber() - tvEpisode2.getNumber();
        }
    };

    public static boolean containSection(SectionInterface section, ArrayList<SectionInterface> sectionList) {
        boolean containsSection = false;
        for (SectionInterface sec : sectionList) {
            if (section.getName().equals(sec.getName())) {
                containsSection = true;
                break;
            }
        }
        return containsSection;
    }
}