Java tutorial
/* * Copyright 2011 daniele.belletti@gmail.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * under the License. */ package it.gnappuraz.netflixsubs.opensubtitles.api; import it.gnappuraz.netflixsubs.types.SubtitleEntry; import it.gnappuraz.netflixsubs.types.SubtitleLink; import org.apache.log4j.Logger; import org.apache.ws.commons.util.Base64; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import java.util.zip.GZIPInputStream; /** * * @author daniele.belletti@gmail.com */ @SuppressWarnings("ALL") @Service public class OpenSubtitlesAPIClient { private static final Logger log = Logger.getLogger(OpenSubtitlesAPIClient.class); private static final String USER_AGENT = "jOSAPI 1.0"; //private static final String USER_AGENT = "OS Test User Agent"; private static final String END_POINT = "http://api.opensubtitles.org/xml-rpc"; private static final String LANGUAGE = "it"; private XmlRpcClient client; private String token; @PostConstruct private void postConstruct() { client = new XmlRpcClient(); XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); try { config.setServerURL(new URL(END_POINT)); } catch (MalformedURLException e) { log.error("MalformedURLException " + END_POINT, e); } client.setConfig(config); client.setTypeFactory(new TypeFactory(client)); try { token = login("", ""); log.info("Logged in with token:" + token); } catch (OpenSubtitlesException e) { log.fatal("Cannot login", e); } } private String login(String username, String password) throws OpenSubtitlesException { List<String> params = new ArrayList<String>(); params.add(username); params.add(password); params.add(LANGUAGE); params.add(USER_AGENT); Map<String, Object> result = executeAPI(API.LOGIN, params); if (result.get("token") == null) { throw new OpenSubtitlesException("login error: token is null"); } String token = (String) result.get("token"); return token; } @PreDestroy private void logout() throws OpenSubtitlesException { List<String> params = new ArrayList<String>(); params.add(token); executeAPI(API.LOGOUT, params); } public List<SubtitleEntry> search(File movie, Language language) throws OpenSubtitlesException { Language[] languageses = { language }; return search(movie, languageses); } public List<SubtitleEntry> search(String title, String season, String episode, Language language) throws OpenSubtitlesException { Language[] languageses = { language }; return search(title, season, episode, languageses); } public List<SubtitleEntry> search(String title, String season, String episode, Language[] languageses) throws OpenSubtitlesException { List<Object> request = APIRequestBuilder.create(token).addLanguages(languageses).addTitle(title) .addSeason(season).addEpisode(episode).getRequest(); Map<String, Object> response = executeAPI(API.SEARCH, request); return convertResponse(response); } public List<SubtitleEntry> search(File movie, Language[] languageses) throws OpenSubtitlesException { try { List<Object> request = APIRequestBuilder.create(token).addLanguages(languageses).addMovieHash(movie) .getRequest(); Map<String, Object> response = executeAPI(API.SEARCH, request); return convertResponse(response); } catch (IOException e) { throw new OpenSubtitlesException("search error", e); } } private List<SubtitleEntry> convertResponse(Map<String, Object> response) { List<SubtitleEntry> results = new ArrayList<SubtitleEntry>(); Object resObject = (Object) response.get("data"); if (resObject instanceof Object[]) { Object[] data = (Object[]) resObject; for (Object o : data) { Map<String, Object> entry = (Map<String, Object>) o; //TODO add support for multi language SubtitleLink lnk = new SubtitleLink((String) entry.get("SubLanguageID"), (String) entry.get("LanguageName"), (String) entry.get("IDSubtitleFile")); SubtitleEntry e = new SubtitleEntry((String) entry.get("SubFileName"), "www.opensubtitles.org", Arrays.asList(lnk)); results.add(e); } } else if (resObject instanceof Boolean) { Boolean result = (Boolean) resObject; if (!result) { log.info("No results found"); } } else { throw new RuntimeException("Not know object type: " + resObject.getClass()); } return results; } public Map<Integer, byte[]> download(Integer... id) throws OpenSubtitlesException { Map<Integer, byte[]> result = new HashMap<Integer, byte[]>(); List<Object> params = new ArrayList<Object>(); List<Integer> ids = new ArrayList<Integer>(); ids.addAll(Arrays.asList(id)); params.add(token); params.add(ids); Map<String, Object> temp = executeAPI(API.DOWNLOAD, params); Object[] data = (Object[]) temp.get("data"); try { for (Object o : data) { temp = (Map<String, Object>) o; byte[] decodedBytes = base64decode((String) temp.get("data")); byte[] subtitle = gunzip(decodedBytes); result.put(new Integer(temp.get("idsubtitlefile") + ""), subtitle); } } catch (Exception e) { throw new OpenSubtitlesException("download error", e); } return result; } private byte[] base64decode(String encoded) throws IOException { byte[] output = Base64.decode(encoded); return output; } private byte[] gunzip(byte[] compressed) throws IOException { GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(compressed)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStream out = new BufferedOutputStream(baos); byte[] buffer = new byte[1024]; while (true) { synchronized (buffer) { int amountRead = gis.read(buffer); if (amountRead == -1) { break; } out.write(buffer, 0, amountRead); } } out.flush(); out.close(); return baos.toByteArray(); } private Map<String, Object> executeAPI(API api, List<?> params) throws OpenSubtitlesException { Map<String, Object> result = null; try { result = (Map) client.execute(api.toString(), params); String statusString = (String) result.get("status"); Status status = Status.fromCode(getCode(statusString)); if (!status.isSuccess()) { throw new OpenSubtitlesException(statusString); } } catch (Exception ex) { throw new OpenSubtitlesException("excuteAPI error: " + api, ex); } return result; } private String getCode(String statusMessage) { return statusMessage.split(" ", 2)[0]; } private String getMessage(String statusMessage) { return statusMessage.split(" ", 2)[1]; } private enum API { LOGIN("LogIn"), SEARCH("SearchSubtitles"), DOWNLOAD("DownloadSubtitles"), LOGOUT("LogOut"); private String functionName; API(String functionName) { this.functionName = functionName; } @Override public String toString() { return functionName; } } }