/** * This method populates the supplied {@link OutputParams} object with the correct subtitles (sid) * based on the given filename, its MediaInfo metadata and PMS configuration settings. * * <p>TODO: Rewrite this crazy method to be more concise and logical. * * @param fileName The file name used to determine the availability of subtitles. * @param media The MediaInfo metadata for the file. * @param params The parameters to populate. */ public static void setSubtitleOutputParameters( String fileName, DLNAMediaInfo media, OutputParams params) { PmsConfiguration configuration = PMS.getConfiguration(params); String currentLang = null; DLNAMediaSubtitle matchedSub = null; if (params.aid != null) { currentLang = params.aid.getLang(); } if (params.sid != null && params.sid.getId() == -1) { LOGGER.trace("Don't want subtitles!"); params.sid = null; return; } /** Check for live subtitles */ if (params.sid != null && !StringUtils.isEmpty(params.sid.getLiveSubURL())) { LOGGER.debug("Live subtitles " + params.sid.getLiveSubURL()); try { matchedSub = params.sid; String file = OpenSubtitle.fetchSubs(matchedSub.getLiveSubURL(), matchedSub.getLiveSubFile()); if (!StringUtils.isEmpty(file)) { matchedSub.setExternalFile(new File(file)); params.sid = matchedSub; return; } } catch (IOException e) { } } StringTokenizer st = new StringTokenizer(configuration.getAudioSubLanguages(), ";"); /** Check for external and internal subtitles matching the user's language preferences */ boolean matchedInternalSubtitles = false; boolean matchedExternalSubtitles = false; while (st.hasMoreTokens()) { String pair = st.nextToken(); if (pair.contains(",")) { String audio = pair.substring(0, pair.indexOf(',')); String sub = pair.substring(pair.indexOf(',') + 1); audio = audio.trim(); sub = sub.trim(); LOGGER.trace( "Searching for a match for: " + currentLang + " with " + audio + " and " + sub); if (Iso639.isCodesMatching(audio, currentLang) || (currentLang != null && audio.equals("*"))) { if (sub.equals("off")) { /** * Ignore the "off" language for external subtitles if the user setting is enabled TODO: * Prioritize multiple external subtitles properly instead of just taking the first one * we load */ if (configuration.isForceExternalSubtitles()) { for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) { if (present_sub.getExternalFile() != null) { matchedSub = present_sub; matchedExternalSubtitles = true; LOGGER.trace( "Ignoring the \"off\" language because there are external subtitles"); break; } } } if (!matchedExternalSubtitles) { matchedSub = new DLNAMediaSubtitle(); matchedSub.setLang("off"); } } else { for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) { if (present_sub.matchCode(sub) || sub.equals("*")) { if (present_sub.getExternalFile() != null) { if (configuration.isAutoloadExternalSubtitles()) { // Subtitle is external and we want external subtitles, look no further matchedSub = present_sub; LOGGER.trace("Matched external subtitles track: " + matchedSub); break; } else { // Subtitle is external but we do not want external subtitles, keep searching LOGGER.trace( "External subtitles ignored because of user setting: " + present_sub); } } else if (!matchedInternalSubtitles) { matchedSub = present_sub; LOGGER.trace("Matched internal subtitles track: " + matchedSub); if (configuration.isAutoloadExternalSubtitles()) { // Subtitle is internal and we will wait to see if an external one is available // instead matchedInternalSubtitles = true; } else { // Subtitle is internal and we will use it break; } } } } } if (matchedSub != null && !matchedInternalSubtitles) { break; } } } } /** * Check for external subtitles that were skipped in the above code block because they didn't * match language preferences, if there wasn't already a match and the user settings specify it. */ if (matchedSub == null && configuration.isForceExternalSubtitles()) { for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) { if (present_sub.getExternalFile() != null) { matchedSub = present_sub; LOGGER.trace( "Matched external subtitles track that did not match language preferences: " + matchedSub); break; } } } /** * Disable chosen subtitles if the user has disabled all subtitles or if the language * preferences have specified the "off" language. * * <p>TODO: Can't we save a bunch of looping by checking for isDisableSubtitles just after the * Live Subtitles check above? */ if (matchedSub != null && params.sid == null) { if (configuration.isDisableSubtitles() || (matchedSub.getLang() != null && matchedSub.getLang().equals("off"))) { LOGGER.trace("Disabled the subtitles: " + matchedSub); } else { params.sid = matchedSub; } } /** Check for forced subtitles. */ if (!configuration.isDisableSubtitles() && params.sid == null && media != null) { // Check for subtitles again File video = new File(fileName); FileUtil.isSubtitlesExists(video, media, false); if (configuration.isAutoloadExternalSubtitles()) { boolean forcedSubsFound = false; // Priority to external subtitles for (DLNAMediaSubtitle sub : media.getSubtitleTracksList()) { if (matchedSub != null && matchedSub.getLang() != null && matchedSub.getLang().equals("off")) { st = new StringTokenizer(configuration.getForcedSubtitleTags(), ","); while (sub.getSubtitlesTrackTitleFromMetadata() != null && st.hasMoreTokens()) { String forcedTags = st.nextToken(); forcedTags = forcedTags.trim(); if (sub.getSubtitlesTrackTitleFromMetadata().toLowerCase().contains(forcedTags) && Iso639.isCodesMatching( sub.getLang(), configuration.getForcedSubtitleLanguage())) { LOGGER.trace( "Forcing preferred subtitles: " + sub.getLang() + "/" + sub.getSubtitlesTrackTitleFromMetadata()); LOGGER.trace("Forced subtitles track: " + sub); if (sub.getExternalFile() != null) { LOGGER.trace( "Found external forced file: " + sub.getExternalFile().getAbsolutePath()); } params.sid = sub; forcedSubsFound = true; break; } } if (forcedSubsFound == true) { break; } } else { LOGGER.trace("Found subtitles track: " + sub); if (sub.getExternalFile() != null) { LOGGER.trace("Found external file: " + sub.getExternalFile().getAbsolutePath()); params.sid = sub; break; } } } } if (matchedSub != null && matchedSub.getLang() != null && matchedSub.getLang().equals("off")) { return; } if (params.sid == null) { st = new StringTokenizer(UMSUtils.getLangList(params.mediaRenderer), ","); while (st.hasMoreTokens()) { String lang = st.nextToken(); lang = lang.trim(); LOGGER.trace("Looking for a subtitle track with lang: " + lang); for (DLNAMediaSubtitle sub : media.getSubtitleTracksList()) { if (sub.matchCode(lang) && !(!configuration.isAutoloadExternalSubtitles() && sub.getExternalFile() != null)) { params.sid = sub; LOGGER.trace("Matched subtitles track: " + params.sid); return; } } } } } }