/* * This file is part of Popcorn Time. * * Popcorn Time 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. * * Popcorn Time 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 Popcorn Time. If not, see <http://www.gnu.org/licenses/>. */ package pct.droid.base.providers.subs; import android.content.Context; import com.squareup.okhttp.Call; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import pct.droid.base.PopcornApplication; import pct.droid.base.content.preferences.Prefs; import pct.droid.base.providers.BaseProvider; import pct.droid.base.providers.media.models.Episode; import pct.droid.base.providers.media.models.Media; import pct.droid.base.providers.media.models.Movie; import pct.droid.base.subs.FatalParsingException; import pct.droid.base.subs.FormatASS; import pct.droid.base.subs.FormatSRT; import pct.droid.base.subs.TimedTextObject; import pct.droid.base.utils.FileUtils; import pct.droid.base.utils.PrefUtils; import pct.droid.base.utils.StorageUtils; public abstract class SubsProvider extends BaseProvider { public static final String SUBS_CALL = "subs_http_call"; public static final String SUBTITLE_LANGUAGE_NONE = "no-subs"; private static List<String> SUB_EXTENSIONS = Arrays.asList("srt", "ssa", "ass"); public abstract void getList(Movie movie, Callback callback); public abstract void getList(Episode episode, Callback callback); public interface Callback { void onSuccess(Map<String, String> items); void onFailure(Exception e); } public static File getStorageLocation(Context context) { return new File(PrefUtils.get(context, Prefs.STORAGE_LOCATION, StorageUtils.getIdealCacheDirectory(context).toString()) + "/subs/"); } /** * @param context Context * @param media Media data * @param languageCode Code of language * @param callback Network callback * @return Call */ public static Call download(final Context context, final Media media, final String languageCode, final com.squareup.okhttp.Callback callback) { OkHttpClient client = PopcornApplication.getHttpClient(); if (media.subtitles != null && media.subtitles.containsKey(languageCode)) { try { Request request = new Request.Builder().url(media.subtitles.get(languageCode)).build(); Call call = client.newCall(request); final File subsDirectory = getStorageLocation(context); final String fileName = media.videoId + "-" + languageCode; final File srtPath = new File(subsDirectory, fileName + ".srt"); if (srtPath.exists()) { callback.onResponse(null); return call; } call.enqueue(new com.squareup.okhttp.Callback() { @Override public void onFailure(Request request, IOException e) { callback.onFailure(request, e); } @Override public void onResponse(Response response) throws IOException { if (response.isSuccessful()) { InputStream inputStream = null; boolean failure = false; try { subsDirectory.mkdirs(); if (srtPath.exists()) { File to = new File(subsDirectory, "temp" + System.currentTimeMillis()); srtPath.renameTo(to); to.delete(); } inputStream = response.body().byteStream(); String urlString = response.request().urlString(); if (urlString.contains(".zip") || urlString.contains(".gz")) { SubsProvider.unpack(inputStream, srtPath, languageCode); } else if (SubsProvider.isSubFormat(urlString)) { parseFormatAndSave(urlString, srtPath, languageCode, inputStream); } else { callback.onFailure(response.request(), new IOException("FatalParsingException")); failure = true; } } catch (FatalParsingException e) { e.printStackTrace(); callback.onFailure(response.request(), new IOException("FatalParsingException")); failure = true; } catch (FileNotFoundException e) { e.printStackTrace(); callback.onFailure(response.request(), e); failure = true; } catch (IOException e) { e.printStackTrace(); callback.onFailure(response.request(), e); failure = true; } finally { if (inputStream != null) inputStream.close(); if (!failure) callback.onResponse(response); } } else { callback.onFailure(response.request(), new IOException("Unknown error")); } } }); return call; } catch (RuntimeException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } callback.onFailure(null, new IOException("Wrong media")); return null; } /** * Unpack ZIP and save SRT * * @param is InputStream from network * @param srtPath Path where SRT should be saved * @param languageCode The language code * @throws IOException * @throws FatalParsingException */ private static void unpack(InputStream is, File srtPath, String languageCode) throws IOException, FatalParsingException { String filename; ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is)); ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { filename = ze.getName(); if (filename.contains("_MACOSX")) continue; if (isSubFormat(filename)) { parseFormatAndSave(filename, srtPath, languageCode, zis); try { zis.closeEntry(); } catch (IOException e) { e.printStackTrace(); } return; } } zis.close(); } /** * Test if file is subtitle format * * @param filename Name of file * @return is subtitle? */ private static boolean isSubFormat(String filename) { for (String ext : SUB_EXTENSIONS) { if (filename.contains("." + ext)) { return true; } } return false; } /** * Parse the text, convert and save to SRT file * * @param inputUrl Original network location * @param srtPath Place where SRT should be saved * @param languageCode The language code * @param inputStream InputStream of data @throws IOException */ private static void parseFormatAndSave(String inputUrl, File srtPath, String languageCode, InputStream inputStream) throws IOException { TimedTextObject subtitleObject = null; String inputString = FileUtils.inputstreamToCharsetString(inputStream, languageCode); String[] inputText = inputString.split("\n|\r\n"); if (inputUrl.contains(".ass") || inputUrl.contains(".ssa")) { FormatASS formatASS = new FormatASS(); subtitleObject = formatASS.parseFile(inputUrl, inputText); } else if (inputUrl.contains(".srt")) { FormatSRT formatSRT = new FormatSRT(); subtitleObject = formatSRT.parseFile(inputUrl, inputText); } if (subtitleObject != null) { FileUtils.saveStringFile(subtitleObject.toSRT(), srtPath); } } }