Example #1
0
 def test_converter_alpha2(self):
     self.assertEqual(Language('eng').alpha2, 'en')
     self.assertEqual(Language.fromalpha2('en'), Language('eng'))
     self.assertEqual(Language.fromcode('en', 'alpha2'), Language('eng'))
     self.assertRaises(LanguageReverseError, lambda: Language.fromalpha2('zz'))
     self.assertRaises(LanguageConvertError, lambda: Language('aaa').alpha2)
     self.assertEqual(len(language_converters['alpha2'].codes), 184)
Example #2
0
def get_subtitle_list(movie_title, source_language_code,
                      destination_language_code):
    video = Video.fromname(movie_title)
    return list_subtitles(
        [video], {
            Language.fromalpha2(source_language_code),
            Language.fromalpha2(destination_language_code)
        }, FreePool)[video]
Example #3
0
 def test_converter_alpha2(self):
     self.assertEqual(Language('eng').alpha2, 'en')
     self.assertEqual(Language.fromalpha2('en'), Language('eng'))
     self.assertEqual(Language.fromcode('en', 'alpha2'), Language('eng'))
     with self.assertRaises(LanguageReverseError):
         Language.fromalpha2('zz')
     with self.assertRaises(LanguageConvertError):
         Language('aaa').alpha2
     self.assertEqual(len(get_language_converter('alpha2').codes), 184)
Example #4
0
    def query(self, searchword=None):
        params = {"searchword": searchword}
        logger.info("Searching subtitles %r", params)

        r = self.session.get("http://sub.makedie.me/sub/?", params=params, timeout=10)
        r.raise_for_status()

        # loop over
        subtitles = []
        try:
            # BeautifulSoup gives you Unicode, damn it
            soup = BeautifulSoup(r.content, "html5lib")
            results = soup.find_all("div", attrs={"class": "subitem"})
            for it in results:
                releases = it.find("a", attrs={"class": "introtitle"})["title"].strip().split("/")
                sid = re.search("/xml/sub/\d+/(\d+).xml", it.find("a", attrs={"class": "introtitle"})["href"]).group(1)

                download_button = it.find("a", attrs={"id": "downsubbtn"})["onclick"].strip()
                if re.search("location.href\s*=\s*", download_button):
                    link = "http://sub.makedie.me/" + re.search(
                        "location.href\s*=\s*['\"](.*?)['\"]", download_button
                    ).group(1)
                else:
                    logger.debug("No download link found")
                    continue

                lang = ""
                for li in it.find_all("li"):
                    if re.search("格式:", li.text.strip()):
                        subtype = re.search("格式:\s*([^\(]+)(?:\(\?\))*", li.text.strip()).group(1)

                    if re.search("语言:", li.text.strip()):
                        lang = re.search("语言:\s*([^\(]+)(?:\(\?\))*", li.text.strip()).group(1)

                    if re.search("下载次数:", li.text.strip()):
                        downloads = re.search("下载次数:\s*([^\(]+)(?:\(\?\))*", li.text.strip()).group(1)
                        downloads = re.search("(\d+).*", downloads).group(1)

                    if re.search("日期:", li.text.strip()):
                        upload_date = re.search("日期:\s*([^\(]+)(?:\(\?\))*", li.text.strip()).group(1)

                if "简" in lang or "繁" in lang or "双语" in lang:
                    subtitle = MakeDieSubtitle(
                        Language.fromalpha2("zh"), releases, sid, link, subtype, downloads, upload_date
                    )
                else:
                    subtitle = MakeDieSubtitle(
                        Language.fromalpha2("en"), releases, sid, link, subtype, downloads, upload_date
                    )

                logger.debug("Found subtitle %r", subtitle)
                subtitles.append(subtitle)

            return subtitles
        except:
            logger.debug("No subtitle found")
            return []
    def checkLanguage(self, language):
        if not language:
            return None

        if len(language) < 2:
            self.log.error("Unable to set tag language [tag-language].")
            return None

        try:
            from babelfish import Language
        except:
            self.log.exception(
                "Unable to important Language from babelfish [tag-language].")
            return None
        if len(language) == 2:
            try:
                return Language.fromalpha2(language).alpha3
                self.log.exception(
                    "Unable to set tag language [tag-language].")
            except:
                return None
        try:
            return Language(language).alpha3
        except:
            self.log.exception("Unable to set tag language [tag-language].")
            return None
Example #6
0
def getAlpha3TCode(code):  # We need to make sure that language codes are alpha3T
    """
        :param    code: Alpha2, Alpha3, or Alpha3b code.
        :type     code: C{str}

        :return: Alpha3t language code (ISO 639-2/T) as C{str}
    """
    lang = 'und'
    code = code.strip().lower()

    if len(code) == 3:
        try:
            lang = Language(code).alpha3t
        except:
            try:
                lang = Language.fromalpha3b(code).alpha3t
            except:
                try:
                    lang = Language.fromalpha3t(code).alpha3t
                except:
                    pass

    elif len(code) == 2:
        lang = Language.fromalpha2(code).alpha3t

    return lang
Example #7
0
    def query(self,
              title,
              season=None,
              episode=None,
              year=None,
              filename=None,
              imdb_id=None):
        # search for the IMDB ID if needed.
        is_movie = not (season and episode)
        imdb_id = imdb_id or self._search_imdb_id(title, year, is_movie)
        if not imdb_id:
            return {}

        # search
        logger.debug('Using IMDB ID %r', imdb_id)
        url = 'https://json.{}/{}.json'.format(self.server_url, imdb_id)
        page_link = 'https://{}/#/{}/{}'.format(
            self.server_url, 'movies' if is_movie else 'series', imdb_id)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        try:
            results = r.json()
        except ValueError:
            return {}

        # filter irrelevant results
        if not is_movie:
            results = results.get('subs', {}).get(str(season),
                                                  {}).get(str(episode), [])
        else:
            results = results.get('subs', [])

        # loop over results
        subtitles = {}
        for result in results:
            language = Language.fromalpha2('he')
            hearing_impaired = False
            subtitle_id = result['id']
            release = result['version']

            # add the release and increment downloaded count if we already have the subtitle
            if subtitle_id in subtitles:
                logger.debug('Found additional release %r for subtitle %d',
                             release, subtitle_id)
                bisect.insort_left(subtitles[subtitle_id].releases,
                                   release)  # deterministic order
                subtitles[subtitle_id].downloaded += 1
                continue

            # otherwise create it
            subtitle = WizdomSubtitle(language, hearing_impaired, page_link,
                                      title, season, episode, title, imdb_id,
                                      subtitle_id, [release])
            logger.debug('Found subtitle %r', subtitle)
            subtitles[subtitle_id] = subtitle

        return subtitles.values()
def getAlpha3TCode(code):  # We need to make sure that language codes are alpha3T
    """
        :param    code: Alpha2, Alpha3, or Alpha3b code.
        :type     code: C{str}

        :return: Alpha3t language code (ISO 639-2/T) as C{str}
    """
    lang = 'und'
    code = code.strip().lower()

    if len(code) == 3:
        try:
            lang = Language(code).alpha3t
        except:
            try:
                lang = Language.fromalpha3b(code).alpha3t
            except:
                try:
                    lang = Language.fromalpha3t(code).alpha3t
                except:
                    pass

    elif len(code) == 2:
        lang = Language.fromalpha2(code).alpha3t

    return lang
Example #9
0
def test_get_matches_episode(episodes):
    subtitle = ArgenteamSubtitle(Language.fromalpha2('es'), None,
                                 'Game of Thrones', 3, 10, 'EVOLVE', '720p')
    matches = subtitle.get_matches(episodes['got_s03e10'])
    assert matches == {
        'resolution', 'series', 'season', 'episode', 'year', 'country'
    }
Example #10
0
class TheSubDBProvider(Provider):
    languages = {
        Language.fromalpha2(l)
        for l in ['en', 'es', 'fr', 'it', 'nl', 'pl', 'pt', 'ro', 'sv', 'tr']
    }
    required_hash = 'thesubdb'
    server_url = 'http://api.thesubdb.com/'

    def initialize(self):
        self.session = Session()
        self.session.headers = {
            'User-Agent':
            'SubDB/1.0 (subliminal/%s; https://github.com/Diaoul/subliminal)' %
            get_version(__version__)
        }

    def terminate(self):
        self.session.close()

    def query(self, hash):
        # make the query
        params = {'action': 'search', 'hash': hash}
        logger.info('Searching subtitles %r', params)
        r = self.session.get(self.server_url, params=params, timeout=10)

        # handle subtitles not found and errors
        if r.status_code == 404:
            logger.debug('No subtitles found')
            return []
        r.raise_for_status()

        # loop over languages
        subtitles = []
        for language_code in r.text.split(','):
            language = Language.fromalpha2(language_code)

            subtitle = TheSubDBSubtitle(language, hash)
            logger.info('Found subtitle %r', subtitle)
            subtitles.append(subtitle)

        return subtitles

    def list_subtitles(self, video, languages):
        return [
            s for s in self.query(video.hashes['thesubdb'])
            if s.language in languages
        ]

    def download_subtitle(self, subtitle):
        logger.info('Downloading subtitle %r')
        params = {
            'action': 'download',
            'hash': subtitle.hash,
            'language': subtitle.language.alpha2
        }
        r = self.session.get(self.server_url, params=params, timeout=10)
        r.raise_for_status()

        subtitle.content = fix_line_ending(r.content)
Example #11
0
def test_download_subtitle(episodes):
    video = episodes['bbt_s07e05']
    languages = {Language.fromalpha2('es')}
    with ArgenteamProvider() as provider:
        subtitles = provider.list_subtitles(video, languages)
        provider.download_subtitle(subtitles[0])
    assert subtitles[0].content is not None
    assert subtitles[0].is_valid() is True
Example #12
0
    def query(self, title, season=None, episode=None):
        # search for the url title
        url_titles = self._search_url_titles(title)

        # episode
        if season and episode:
            if 'series' not in url_titles:
                logger.error('No URL title found for series %r', title)
                return []
            url_title = url_titles['series'][0]
            logger.debug('Using series title %r', url_title)
            url = self.server_url + 'cst/data/series/sb/{}/{}/{}/'.format(url_title, season, episode)
            page_link = self.server_url + 'subtitle/series/{}/{}/{}/'.format(url_title, season, episode)
        else:
            if 'movie' not in url_titles:
                logger.error('No URL title found for movie %r', title)
                return []
            url_title = url_titles['movie'][0]
            logger.debug('Using movie title %r', url_title)
            url = self.server_url + 'cst/data/movie/sb/{}/'.format(url_title)
            page_link = self.server_url + 'subtitle/movie/{}/'.format(url_title)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        subtitle_version = subtitle_item['h_version']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug('Found additional release %r for subtitle %d', release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases, release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(language, hearing_impaired, page_link, title, season, episode,
                                                      title, subtitle_id, subtitle_key, subtitle_version, downloaded,
                                                      [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()
Example #13
0
    def query(self, title, season=None, episode=None):
        # search for the url title
        url_titles = self._search_url_titles(title)

        # episode
        if season and episode:
            if 'series' not in url_titles:
                logger.error('No URL title found for series %r', title)
                return []
            url_title = url_titles['series'][0]
            logger.debug('Using series title %r', url_title)
            url = self.server_url + 'cst/data/series/sb/{}/{}/{}/'.format(url_title, season, episode)
            page_link = self.server_url + 'subtitle/series/{}/{}/{}/'.format(url_title, season, episode)
        else:
            if 'movie' not in url_titles:
                logger.error('No URL title found for movie %r', title)
                return []
            url_title = url_titles['movie'][0]
            logger.debug('Using movie title %r', url_title)
            url = self.server_url + 'cst/data/movie/sb/{}/'.format(url_title)
            page_link = self.server_url + 'subtitle/movie/{}/'.format(url_title)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        subtitle_version = subtitle_item['h_version']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug('Found additional release %r for subtitle %d', release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases, release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(language, hearing_impaired, page_link, title, season, episode,
                                                      title, subtitle_id, subtitle_key, subtitle_version, downloaded,
                                                      [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()
Example #14
0
    def query(self, series=None, season=None, episode=None, title=None):
        # set the correct parameters depending on the kind
        if series and season and episode:
            url_series = self._search_url_title(series, 'series')
            url = self.server_url + 'cinemast/data/series/sb/{}/{}/{}/'.format(
                url_series, season, episode)
            page_link = self.server_url + 'subtitle/series/{}/{}/{}/'.format(
                url_series, season, episode)
        elif title:
            url_title = self._search_url_title(title, 'movie')
            url = self.server_url + 'cinemast/data/movie/sb/{}/'.format(
                url_title)
            page_link = self.server_url + 'subtitle/movie/{}/'.format(
                url_title)
        else:
            raise ValueError('One or more parameters are missing')

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(
                            subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug(
                                'Found additional release %r for subtitle %d',
                                release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases,
                                               release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(
                            language, hearing_impaired, page_link, series,
                            season, episode, title, subtitle_id, subtitle_key,
                            downloaded, [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()
Example #15
0
class NapiProjektProvider(Provider):
    """NapiProjekt Provider."""
    languages = {Language.fromalpha2(l) for l in ['pl']}
    required_hash = 'napiprojekt'
    server_url = 'http://napiprojekt.pl/unit_napisy/dl.php'
    subtitle_class = NapiProjektSubtitle

    def __init__(self):
        self.session = None

    def initialize(self):
        self.session = Session()
        self.session.headers[
            'User-Agent'] = 'Subliminal/%s' % __short_version__

    def terminate(self):
        self.session.close()

    def query(self, language, hash):
        params = {
            'v': 'dreambox',
            'kolejka': 'false',
            'nick': '',
            'pass': '',
            'napios': 'Linux',
            'l': language.alpha2.upper(),
            'f': hash,
            't': get_subhash(hash)
        }
        logger.info('Searching subtitle %r', params)
        r = self.session.get(self.server_url, params=params, timeout=10)
        r.raise_for_status()

        # handle subtitles not found and errors
        if r.content[:4] == b'NPc0':
            logger.debug('No subtitles found')
            return None

        subtitle = self.subtitle_class(language, hash)
        subtitle.content = r.content
        logger.debug('Found subtitle %r', subtitle)

        return subtitle

    def list_subtitles(self, video, languages):
        return [
            s for s in
            [self.query(l, video.hashes['napiprojekt']) for l in languages]
            if s is not None
        ]

    def download_subtitle(self, subtitle):
        # there is no download step, content is already filled from listing subtitles
        pass
Example #16
0
def test_list_subtitles_episode_alternative_series(episodes):
    video = episodes['turn_s04e03']
    languages = {Language.fromalpha2('es')}
    expected_subtitles = {
        'http://www.argenteam.net/subtitles/67263/TURN.Washingtons.Spies.%282014%29.S04E03'
        '-Blood.for.Blood.HDTV.x264-SVA',
        'http://www.argenteam.net/subtitles/67264/TURN.Washingtons.Spies.%282014%29.S04E03'
        '-Blood.for.Blood.HDTV.x264.720p-AVS'
    }
    with ArgenteamProvider() as provider:
        subtitles = provider.list_subtitles(video, languages)
    assert {s.id for s in subtitles} == expected_subtitles
Example #17
0
    def query(self, title, season=None, episode=None, year=None, filename=None, imdb_id=None):
        # search for the IMDB ID if needed.
        is_movie = not (season and episode)
        imdb_id = imdb_id or self._search_imdb_id(title, year, is_movie)
        if not imdb_id:
            return {}

        # search
        logger.debug('Using IMDB ID %r', imdb_id)
        url = 'http://json.{}/{}.json'.format(self.server_url, imdb_id)
        page_link = 'http://{}/#/{}/{}'.format(self.server_url, 'movies' if is_movie else 'series', imdb_id)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        try:
            results = r.json()
        except ValueError:
            return {}

        # filter irrelevant results
        if not is_movie:
            results = results.get('subs', {}).get(str(season), {}).get(str(episode), [])
        else:
            results = results.get('subs', [])

        # loop over results
        subtitles = {}
        for result in results:
            language = Language.fromalpha2('he')
            hearing_impaired = False
            subtitle_id = result['id']
            release = result['version']

            # add the release and increment downloaded count if we already have the subtitle
            if subtitle_id in subtitles:
                logger.debug('Found additional release %r for subtitle %d', release, subtitle_id)
                bisect.insort_left(subtitles[subtitle_id].releases, release)  # deterministic order
                subtitles[subtitle_id].downloaded += 1
                continue

            # otherwise create it
            subtitle = WizdomSubtitle(language, hearing_impaired, page_link, title, season, episode, title, imdb_id,
                                      subtitle_id, [release])
            logger.debug('Found subtitle %r', subtitle)
            subtitles[subtitle_id] = subtitle

        return subtitles.values()
Example #18
0
    def query(self, series=None, season=None, episode=None, title=None):
        # set the correct parameters depending on the kind
        if series and season and episode:
            url_series = self._search_url_title(series, 'series')
            url = self.server + 'cinemast/data/series/sb/{}/{}/{}/'.format(url_series, season, episode)
            page_link = self.server + 'subtitle/series/{}/{}/{}/'.format(url_series, season, episode)
        elif title:
            url_title = self._search_url_title(title, 'movie')
            url = self.server + 'cinemast/data/movie/sb/{}/'.format(url_title)
            page_link = self.server + 'subtitle/movie/{}/'.format(url_title)
        else:
            raise ValueError('One or more parameters are missing')

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug('Found additional release %r for subtitle %d', release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases, release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(language, hearing_impaired, page_link, series, season, episode,
                                                      title, subtitle_id, subtitle_key, downloaded, [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()
Example #19
0
    def query(self, hash):
        # make the query
        params = {'action': 'search', 'hash': hash}
        logger.info('Searching subtitles %r', params)
        r = self.session.get(self.server_url, params=params, timeout=10)

        # handle subtitles not found and errors
        if r.status_code == 404:
            logger.debug('No subtitles found')
            return []
        r.raise_for_status()

        # loop over languages
        subtitles = []
        for language_code in r.text.split(','):
            language = Language.fromalpha2(language_code)

            subtitle = TheSubDBSubtitle(language, hash)
            logger.info('Found subtitle %r', subtitle)
            subtitles.append(subtitle)

        return subtitles
Example #20
0
    def query(self, hash):
        # make the query
        params = {'action': 'search', 'hash': hash}
        logger.info('Searching subtitles %r', params)
        r = self.session.get(self.server_url, params=params, timeout=10)

        # handle subtitles not found and errors
        if r.status_code == 404:
            logger.debug('No subtitles found')
            return []
        r.raise_for_status()

        # loop over languages
        subtitles = []
        for language_code in r.text.split(','):
            language = Language.fromalpha2(language_code)

            subtitle = TheSubDBSubtitle(language, hash)
            logger.info('Found subtitle %r', subtitle)
            subtitles.append(subtitle)

        return subtitles
Example #21
0
def getAlpha3TCode(code, default=None):
    lang = default or UNDEFINED
    if not code or code == UNDEFINED:
        return lang

    code = code.strip().lower().replace('.', '')

    if len(code) == 3:
        try:
            lang = Language(code).alpha3t
        except:
            try:
                lang = Language.fromalpha3b(code).alpha3t
            except:
                try:
                    lang = Language.fromalpha3t(code).alpha3t
                except:
                    pass
    elif len(code) == 2:
        try:
            lang = Language.fromalpha2(code).alpha3t
        except:
            pass
    return lang
Example #22
0
    def query(self, hash):
        # shooter has many DNS mirrors, e.g. splayer[1-9], but one is enough
        params = {"pathinfo": "temp", "format": "json", "filehash": hash}
        logger.info("Searching subtitles %r", params)

        r = self.session.get("https://www.shooter.cn/api/subapi.php", params=params, timeout=10)
        r.raise_for_status()

        # loop over, server always returns found or not
        subtitles = []
        try:
            for it in r.json():
                # It normally contains one File, but can contain multiple
                link = it["Files"][0]["Link"]
                subtype = it["Files"][0]["Ext"]
                subtitle = ShooterSubtitle(Language.fromalpha2("zh"), hash, link, subtype)
                logger.debug("Found subtitle %r", subtitle)

                subtitles.append(subtitle)

            return subtitles
        except:
            logger.debug("No subtitle found")
            return []
def build_commands(file, new_dir, movie_name, bitbucket):
    if isinstance(file, string_types):
        input_file = file
        if 'concat:' in file:
            file = file.split('|')[0].replace('concat:', '')
        video_details, result = get_video_details(file)
        directory, name = os.path.split(file)
        name, ext = os.path.splitext(name)
        check = re.match('VTS_([0-9][0-9])_[0-9]+', name)
        if check and core.CONCAT:
            name = movie_name
        elif check:
            name = ('{0}.cd{1}'.format(movie_name, check.groups()[0]))
        elif core.CONCAT and re.match('(.+)[cC][dD][0-9]', name):
            name = re.sub('([ ._=:-]+[cC][dD][0-9])', '', name)
        if ext == core.VEXTENSION and new_dir == directory:  # we need to change the name to prevent overwriting itself.
            core.VEXTENSION = '-transcoded{ext}'.format(
                ext=core.VEXTENSION)  # adds '-transcoded.ext'
        new_file = file
    else:
        img, data = next(iteritems(file))
        name = data['name']
        new_file = []
        rem_vid = []
        for vid in data['files']:
            video_details, result = get_video_details(vid, img, bitbucket)
            if not check_vid_file(
                    video_details, result
            ):  #lets not transcode menu or other clips that don't have audio and video.
                rem_vid.append(vid)
        data['files'] = [f for f in data['files'] if f not in rem_vid]
        new_file = {img: {'name': data['name'], 'files': data['files']}}
        video_details, result = get_video_details(data['files'][0], img,
                                                  bitbucket)
        input_file = '-'
        file = '-'

    newfile_path = os.path.normpath(
        os.path.join(new_dir, name) + core.VEXTENSION)

    map_cmd = []
    video_cmd = []
    audio_cmd = []
    audio_cmd2 = []
    sub_cmd = []
    meta_cmd = []
    other_cmd = []

    if not video_details or not video_details.get(
            'streams'
    ):  # we couldn't read streams with ffprobe. Set defaults to try transcoding.
        video_streams = []
        audio_streams = []
        sub_streams = []

        map_cmd.extend(['-map', '0'])
        if core.VCODEC:
            video_cmd.extend(['-c:v', core.VCODEC])
            if core.VCODEC == 'libx264' and core.VPRESET:
                video_cmd.extend(['-pre', core.VPRESET])
        else:
            video_cmd.extend(['-c:v', 'copy'])
        if core.VFRAMERATE:
            video_cmd.extend(['-r', str(core.VFRAMERATE)])
        if core.VBITRATE:
            video_cmd.extend(['-b:v', str(core.VBITRATE)])
        if core.VRESOLUTION:
            video_cmd.extend(
                ['-vf', 'scale={vres}'.format(vres=core.VRESOLUTION)])
        if core.VPRESET:
            video_cmd.extend(['-preset', core.VPRESET])
        if core.VCRF:
            video_cmd.extend(['-crf', str(core.VCRF)])
        if core.VLEVEL:
            video_cmd.extend(['-level', str(core.VLEVEL)])

        if core.ACODEC:
            audio_cmd.extend(['-c:a', core.ACODEC])
            if core.ACODEC in [
                    'aac', 'dts'
            ]:  # Allow users to use the experimental AAC codec that's built into recent versions of ffmpeg
                audio_cmd.extend(['-strict', '-2'])
        else:
            audio_cmd.extend(['-c:a', 'copy'])
        if core.ACHANNELS:
            audio_cmd.extend(['-ac', str(core.ACHANNELS)])
        if core.ABITRATE:
            audio_cmd.extend(['-b:a', str(core.ABITRATE)])
        if core.OUTPUTQUALITYPERCENT:
            audio_cmd.extend(['-q:a', str(core.OUTPUTQUALITYPERCENT)])

        if core.SCODEC and core.ALLOWSUBS:
            sub_cmd.extend(['-c:s', core.SCODEC])
        elif core.ALLOWSUBS:  # Not every subtitle codec can be used for every video container format!
            sub_cmd.extend(['-c:s', 'copy'])
        else:  # http://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options
            sub_cmd.extend(['-sn'])  # Don't copy the subtitles over

        if core.OUTPUTFASTSTART:
            other_cmd.extend(['-movflags', '+faststart'])

    else:
        video_streams = [
            item for item in video_details['streams']
            if item['codec_type'] == 'video'
        ]
        audio_streams = [
            item for item in video_details['streams']
            if item['codec_type'] == 'audio'
        ]
        sub_streams = [
            item for item in video_details['streams']
            if item['codec_type'] == 'subtitle'
        ]
        if core.VEXTENSION not in ['.mkv', '.mpegts']:
            sub_streams = [
                item for item in video_details['streams']
                if item['codec_type'] == 'subtitle' and item['codec_name'] !=
                'hdmv_pgs_subtitle' and item['codec_name'] != 'pgssub'
            ]

    for video in video_streams:
        codec = video['codec_name']
        fr = video.get('avg_frame_rate', 0)
        width = video.get('width', 0)
        height = video.get('height', 0)
        scale = core.VRESOLUTION
        if codec in core.VCODEC_ALLOW or not core.VCODEC:
            video_cmd.extend(['-c:v', 'copy'])
        else:
            video_cmd.extend(['-c:v', core.VCODEC])
        if core.VFRAMERATE and not (core.VFRAMERATE * 0.999 <= fr <=
                                    core.VFRAMERATE * 1.001):
            video_cmd.extend(['-r', str(core.VFRAMERATE)])
        if scale:
            w_scale = width / float(scale.split(':')[0])
            h_scale = height / float(scale.split(':')[1])
            if w_scale > h_scale:  # widescreen, Scale by width only.
                scale = '{width}:{height}'.format(
                    width=scale.split(':')[0],
                    height=int((height / w_scale) / 2) * 2,
                )
                if w_scale > 1:
                    video_cmd.extend(
                        ['-vf', 'scale={width}'.format(width=scale)])
            else:  # lower or matching ratio, scale by height only.
                scale = '{width}:{height}'.format(
                    width=int((width / h_scale) / 2) * 2,
                    height=scale.split(':')[1],
                )
                if h_scale > 1:
                    video_cmd.extend(
                        ['-vf', 'scale={height}'.format(height=scale)])
        if core.VBITRATE:
            video_cmd.extend(['-b:v', str(core.VBITRATE)])
        if core.VPRESET:
            video_cmd.extend(['-preset', core.VPRESET])
        if core.VCRF:
            video_cmd.extend(['-crf', str(core.VCRF)])
        if core.VLEVEL:
            video_cmd.extend(['-level', str(core.VLEVEL)])
        no_copy = ['-vf', '-r', '-crf', '-level', '-preset', '-b:v']
        if video_cmd[1] == 'copy' and any(i in video_cmd for i in no_copy):
            video_cmd[1] = core.VCODEC
        if core.VCODEC == 'copy':  # force copy. therefore ignore all other video transcoding.
            video_cmd = ['-c:v', 'copy']
        map_cmd.extend(['-map', '0:{index}'.format(index=video['index'])])
        break  # Only one video needed

    used_audio = 0
    a_mapped = []
    commentary = []
    if audio_streams:
        for i, val in reversed(list(enumerate(audio_streams))):
            try:
                if 'Commentary' in val.get('tags').get(
                        'title'):  # Split out commentry tracks.
                    commentary.append(val)
                    del audio_streams[i]
            except Exception:
                continue
        try:
            audio1 = [
                item for item in audio_streams
                if item['tags']['language'] == core.ALANGUAGE
            ]
        except Exception:  # no language tags. Assume only 1 language.
            audio1 = audio_streams
        try:
            audio2 = [
                item for item in audio1
                if item['codec_name'] in core.ACODEC_ALLOW
            ]
        except Exception:
            audio2 = []
        try:
            audio3 = [
                item for item in audio_streams
                if item['tags']['language'] != core.ALANGUAGE
            ]
        except Exception:
            audio3 = []
        try:
            audio4 = [
                item for item in audio3
                if item['codec_name'] in core.ACODEC_ALLOW
            ]
        except Exception:
            audio4 = []

        if audio2:  # right (or only) language and codec...
            map_cmd.extend(
                ['-map', '0:{index}'.format(index=audio2[0]['index'])])
            a_mapped.extend([audio2[0]['index']])
            bitrate = int(float(audio2[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio2[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), 'copy'])
        elif audio1:  # right (or only) language, wrong codec.
            map_cmd.extend(
                ['-map', '0:{index}'.format(index=audio1[0]['index'])])
            a_mapped.extend([audio1[0]['index']])
            bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio1[0].get('channels', 0)))
            audio_cmd.extend([
                '-c:a:{0}'.format(used_audio),
                core.ACODEC if core.ACODEC else 'copy'
            ])
        elif audio4:  # wrong language, right codec.
            map_cmd.extend(
                ['-map', '0:{index}'.format(index=audio4[0]['index'])])
            a_mapped.extend([audio4[0]['index']])
            bitrate = int(float(audio4[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio4[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), 'copy'])
        elif audio3:  # wrong language, wrong codec. just pick the default audio track
            map_cmd.extend(
                ['-map', '0:{index}'.format(index=audio3[0]['index'])])
            a_mapped.extend([audio3[0]['index']])
            bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio3[0].get('channels', 0)))
            audio_cmd.extend([
                '-c:a:{0}'.format(used_audio),
                core.ACODEC if core.ACODEC else 'copy'
            ])

        if core.ACHANNELS and channels and channels > core.ACHANNELS:
            audio_cmd.extend(
                ['-ac:a:{0}'.format(used_audio),
                 str(core.ACHANNELS)])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if core.ABITRATE and not (core.ABITRATE * 0.9 < bitrate <
                                  core.ABITRATE * 1.1):
            audio_cmd.extend(
                ['-b:a:{0}'.format(used_audio),
                 str(core.ABITRATE)])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if core.OUTPUTQUALITYPERCENT:
            audio_cmd.extend([
                '-q:a:{0}'.format(used_audio),
                str(core.OUTPUTQUALITYPERCENT)
            ])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if audio_cmd[1] in ['aac', 'dts']:
            audio_cmd[2:2] = ['-strict', '-2']

        if core.ACODEC2_ALLOW:
            used_audio += 1
            try:
                audio5 = [
                    item for item in audio1
                    if item['codec_name'] in core.ACODEC2_ALLOW
                ]
            except Exception:
                audio5 = []
            try:
                audio6 = [
                    item for item in audio3
                    if item['codec_name'] in core.ACODEC2_ALLOW
                ]
            except Exception:
                audio6 = []
            if audio5:  # right language and codec.
                map_cmd.extend(
                    ['-map', '0:{index}'.format(index=audio5[0]['index'])])
                a_mapped.extend([audio5[0]['index']])
                bitrate = int(float(audio5[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio5[0].get('channels', 0)))
                audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio1:  # right language wrong codec.
                map_cmd.extend(
                    ['-map', '0:{index}'.format(index=audio1[0]['index'])])
                a_mapped.extend([audio1[0]['index']])
                bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio1[0].get('channels', 0)))
                if core.ACODEC2:
                    audio_cmd2.extend(
                        ['-c:a:{0}'.format(used_audio), core.ACODEC2])
                else:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio6:  # wrong language, right codec
                map_cmd.extend(
                    ['-map', '0:{index}'.format(index=audio6[0]['index'])])
                a_mapped.extend([audio6[0]['index']])
                bitrate = int(float(audio6[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio6[0].get('channels', 0)))
                audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio3:  # wrong language, wrong codec just pick the default audio track
                map_cmd.extend(
                    ['-map', '0:{index}'.format(index=audio3[0]['index'])])
                a_mapped.extend([audio3[0]['index']])
                bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio3[0].get('channels', 0)))
                if core.ACODEC2:
                    audio_cmd2.extend(
                        ['-c:a:{0}'.format(used_audio), core.ACODEC2])
                else:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])

            if core.ACHANNELS2 and channels and channels > core.ACHANNELS2:
                audio_cmd2.extend(
                    ['-ac:a:{0}'.format(used_audio),
                     str(core.ACHANNELS2)])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if core.ABITRATE2 and not (core.ABITRATE2 * 0.9 < bitrate <
                                       core.ABITRATE2 * 1.1):
                audio_cmd2.extend(
                    ['-b:a:{0}'.format(used_audio),
                     str(core.ABITRATE2)])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if core.OUTPUTQUALITYPERCENT:
                audio_cmd2.extend([
                    '-q:a:{0}'.format(used_audio),
                    str(core.OUTPUTQUALITYPERCENT)
                ])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if audio_cmd2[1] in ['aac', 'dts']:
                audio_cmd2[2:2] = ['-strict', '-2']

            if a_mapped[1] == a_mapped[0] and audio_cmd2[1:] == audio_cmd[
                    1:]:  # check for duplicate output track.
                del map_cmd[-2:]
            else:
                audio_cmd.extend(audio_cmd2)

        if core.AINCLUDE and core.ACODEC3:
            audio_streams.extend(commentary)  # add commentry tracks back here.
            for audio in audio_streams:
                if audio['index'] in a_mapped:
                    continue
                used_audio += 1
                map_cmd.extend(
                    ['-map', '0:{index}'.format(index=audio['index'])])
                audio_cmd3 = []
                bitrate = int(float(audio.get('bit_rate', 0))) / 1000
                channels = int(float(audio.get('channels', 0)))
                if audio['codec_name'] in core.ACODEC3_ALLOW:
                    audio_cmd3.extend(['-c:a:{0}'.format(used_audio), 'copy'])
                else:
                    if core.ACODEC3:
                        audio_cmd3.extend(
                            ['-c:a:{0}'.format(used_audio), core.ACODEC3])
                    else:
                        audio_cmd3.extend(
                            ['-c:a:{0}'.format(used_audio), 'copy'])

                if core.ACHANNELS3 and channels and channels > core.ACHANNELS3:
                    audio_cmd3.extend(
                        ['-ac:a:{0}'.format(used_audio),
                         str(core.ACHANNELS3)])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if core.ABITRATE3 and not (core.ABITRATE3 * 0.9 < bitrate <
                                           core.ABITRATE3 * 1.1):
                    audio_cmd3.extend(
                        ['-b:a:{0}'.format(used_audio),
                         str(core.ABITRATE3)])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if core.OUTPUTQUALITYPERCENT > 0:
                    audio_cmd3.extend([
                        '-q:a:{0}'.format(used_audio),
                        str(core.OUTPUTQUALITYPERCENT)
                    ])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if audio_cmd3[1] in ['aac', 'dts']:
                    audio_cmd3[2:2] = ['-strict', '-2']
                audio_cmd.extend(audio_cmd3)

    s_mapped = []
    burnt = 0
    n = 0
    for lan in core.SLANGUAGES:
        try:
            subs1 = [
                item for item in sub_streams if item['tags']['language'] == lan
            ]
        except Exception:
            subs1 = []
        if core.BURN and not subs1 and not burnt and os.path.isfile(file):
            for subfile in get_subs(file):
                if lan in os.path.split(subfile)[1]:
                    video_cmd.extend(
                        ['-vf', 'subtitles={subs}'.format(subs=subfile)])
                    burnt = 1
        for sub in subs1:
            if core.BURN and not burnt and os.path.isfile(input_file):
                subloc = 0
                for index in range(len(sub_streams)):
                    if sub_streams[index]['index'] == sub['index']:
                        subloc = index
                        break
                video_cmd.extend([
                    '-vf', 'subtitles={sub}:si={loc}'.format(sub=input_file,
                                                             loc=subloc)
                ])
                burnt = 1
            if not core.ALLOWSUBS:
                break
            if sub['codec_name'] in [
                    'dvd_subtitle', 'VobSub'
            ] and core.SCODEC == 'mov_text':  # We can't convert these.
                continue
            map_cmd.extend(['-map', '0:{index}'.format(index=sub['index'])])
            s_mapped.extend([sub['index']])

    if core.SINCLUDE:
        for sub in sub_streams:
            if not core.ALLOWSUBS:
                break
            if sub['index'] in s_mapped:
                continue
            if sub['codec_name'] in [
                    'dvd_subtitle', 'VobSub'
            ] and core.SCODEC == 'mov_text':  # We can't convert these.
                continue
            map_cmd.extend(['-map', '0:{index}'.format(index=sub['index'])])
            s_mapped.extend([sub['index']])

    if core.OUTPUTFASTSTART:
        other_cmd.extend(['-movflags', '+faststart'])
    if core.OTHEROPTS:
        other_cmd.extend(core.OTHEROPTS)

    command = [core.FFMPEG, '-loglevel', 'warning']

    if core.HWACCEL:
        command.extend(['-hwaccel', 'auto'])
    if core.GENERALOPTS:
        command.extend(core.GENERALOPTS)

    command.extend(['-i', input_file])

    if core.SEMBED and os.path.isfile(file):
        for subfile in get_subs(file):
            sub_details, result = get_video_details(subfile)
            if not sub_details or not sub_details.get('streams'):
                continue
            if core.SCODEC == 'mov_text':
                subcode = [
                    stream['codec_name'] for stream in sub_details['streams']
                ]
                if set(subcode).intersection(['dvd_subtitle', 'VobSub'
                                              ]):  # We can't convert these.
                    continue
            command.extend(['-i', subfile])
            lan = os.path.splitext(
                os.path.splitext(subfile)[0])[1][1:].split('-')[0]
            lan = text_type(lan)
            metlan = None
            try:
                if len(lan) == 3:
                    metlan = Language(lan)
                if len(lan) == 2:
                    metlan = Language.fromalpha2(lan)
            except Exception:
                pass
            if metlan:
                meta_cmd.extend([
                    '-metadata:s:s:{x}'.format(x=len(s_mapped) + n),
                    'language={lang}'.format(lang=metlan.alpha3)
                ])
            n += 1
            map_cmd.extend(['-map', '{x}:0'.format(x=n)])

    if not core.ALLOWSUBS or (not s_mapped and not n):
        sub_cmd.extend(['-sn'])
    else:
        if core.SCODEC:
            sub_cmd.extend(['-c:s', core.SCODEC])
        else:
            sub_cmd.extend(['-c:s', 'copy'])

    command.extend(map_cmd)
    command.extend(video_cmd)
    command.extend(audio_cmd)
    command.extend(sub_cmd)
    command.extend(meta_cmd)
    command.extend(other_cmd)
    command.append(newfile_path)
    if platform.system() != 'Windows':
        command = core.NICENESS + command
    return command, new_file
Example #24
0
class PodnapisiProvider(Provider):
    """Podnapisi Provider."""
    languages = ({Language('por', 'BR'),
                  Language('srp', script='Latn')} | {
                      Language.fromalpha2(l)
                      for l in language_converters['alpha2'].codes
                  })
    server_url = 'https://www.podnapisi.net/subtitles/'
    subtitle_class = PodnapisiSubtitle

    def __init__(self):
        self.session = None

    def initialize(self):
        self.session = Session()
        self.session.mount('https://', SecLevelOneTLSAdapter())
        self.session.headers['User-Agent'] = self.user_agent
        self.session.headers['Accept'] = 'application/json'

    def terminate(self):
        self.session.close()

    def query(self, language, keyword, season=None, episode=None, year=None):
        # set parameters, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164#p212652
        params = {'keywords': keyword, 'language': str(language)}
        is_episode = False
        if season is not None and episode:
            is_episode = True
            params['seasons'] = season
            params['episodes'] = episode
            params['movie_type'] = ['tv-series', 'mini-series']
        else:
            params['movie_type'] = 'movie'
        if year:
            params['year'] = year

        # loop over paginated results
        logger.info('Searching subtitles %r', params)
        subtitles = []
        pids = set()
        while True:
            # query the server
            r = self.session.get(self.server_url + 'search/advanced',
                                 params=params,
                                 timeout=10)
            r.raise_for_status()
            result = json.loads(r.text)

            # loop over subtitles
            for data in result['data']:
                # read xml elements
                pid = data['id']
                # ignore duplicates, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164&start=10#p213321
                if pid in pids:
                    logger.debug('Ignoring duplicate %r', pid)
                    continue

                if is_episode and data['movie']['type'] == 'movie':
                    logger.error('Wrong type detected: movie for episode')
                    continue

                language = Language.fromietf(data['language'])
                hearing_impaired = 'hearing_impaired' in data['flags']
                page_link = data['url']
                releases = data['releases'] + data['custom_releases']
                title = data['movie']['title']
                season = int(data['movie']['episode_info'].get(
                    'season')) if is_episode else None
                episode = int(data['movie']['episode_info'].get(
                    'episode')) if is_episode else None
                year = int(data['movie']['year'])

                if is_episode:
                    subtitle = self.subtitle_class(language,
                                                   hearing_impaired,
                                                   page_link,
                                                   pid,
                                                   releases,
                                                   title,
                                                   season=season,
                                                   episode=episode,
                                                   year=year)
                else:
                    subtitle = self.subtitle_class(language,
                                                   hearing_impaired,
                                                   page_link,
                                                   pid,
                                                   releases,
                                                   title,
                                                   year=year)

                logger.debug('Found subtitle %r', subtitle)
                subtitles.append(subtitle)
                pids.add(pid)

            # stop on last page
            if int(result['page']) >= int(result['all_pages']):
                break

            # increment current page
            params['page'] = int(result['page']) + 1
            logger.debug('Getting page %d', params['page'])

        return subtitles

    def list_subtitles(self, video, languages):
        season = episode = None
        if isinstance(video, Episode):
            titles = [video.series] + video.alternative_series
            season = video.season
            episode = video.episode
        else:
            titles = [video.title] + video.alternative_titles

        for title in titles:
            subtitles = [
                s for l in languages for s in self.query(
                    l, title, season=season, episode=episode, year=video.year)
            ]
            if subtitles:
                return subtitles

        return []

    def download_subtitle(self, subtitle):
        # download as a zip
        logger.info('Downloading subtitle %r', subtitle)
        r = self.session.get(self.server_url + subtitle.pid + '/download',
                             params={'container': 'zip'},
                             timeout=10)
        r.raise_for_status()

        # open the zip
        with ZipFile(io.BytesIO(r.content)) as zf:
            if len(zf.namelist()) > 1:
                raise ProviderError('More than one file to unzip')

            subtitle.content = fix_line_ending(zf.read(zf.namelist()[0]))
Example #25
0
class SubsCenterProvider(Provider):
    """SubsCenter Provider."""
    languages = {Language.fromalpha2(l) for l in ['he']}
    server_url = 'http://subscenter.cinemast.com/he/'

    def __init__(self, username=None, password=None):
        if username is not None and password is None or username is None and password is not None:
            raise ConfigurationError('Username and password must be specified')

        self.username = username
        self.password = password
        self.logged_in = False

    def initialize(self):
        self.session = Session()
        self.session.headers[
            'User-Agent'] = 'Subliminal/%s' % __short_version__

        # login
        if self.username is not None and self.password is not None:
            logger.debug('Logging in')
            url = self.server_url + 'subscenter/accounts/login/'

            # retrieve CSRF token
            self.session.get(url)
            csrf_token = self.session.cookies['csrftoken']

            # actual login
            data = {
                'username': self.username,
                'password': self.password,
                'csrfmiddlewaretoken': csrf_token
            }
            r = self.session.post(url, data, allow_redirects=False, timeout=10)

            if r.status_code != 302:
                raise AuthenticationError(self.username)

            logger.info('Logged in')
            self.logged_in = True

    def terminate(self):
        # logout
        if self.logged_in:
            logger.info('Logging out')
            r = self.session.get(self.server_url +
                                 'subscenter/accounts/logout/',
                                 timeout=10)
            r.raise_for_status()
            logger.info('Logged out')
            self.logged_in = False

        self.session.close()

    @region.cache_on_arguments(expiration_time=SHOW_EXPIRATION_TIME)
    def _search_url_title(self, title, kind):
        """Search the URL title for the given `title`.

        :param str title: title to search for.
        :param str kind: kind of the title, ``movie`` or ``series``.
        :return: the URL version of the title.
        :rtype: str

        """
        # make the search
        logger.info('Searching title name for %r', title)
        r = self.session.get(self.server_url + 'subtitle/search/',
                             params={'q': title},
                             allow_redirects=False,
                             timeout=10)
        r.raise_for_status()

        # if redirected, get the url title from the Location header
        if r.is_redirect:
            parts = r.headers['Location'].split('/')

            # check kind
            if parts[-3] == kind:
                return parts[-2]

            return None

        # otherwise, get the first valid suggestion
        soup = ParserBeautifulSoup(r.content, ['lxml', 'html.parser'])
        suggestions = soup.select('#processes div.generalWindowTop a')
        logger.debug('Found %d suggestions', len(suggestions))
        for suggestion in suggestions:
            parts = suggestion.attrs['href'].split('/')

            # check kind
            if parts[-3] == kind:
                return parts[-2]

    def query(self, series=None, season=None, episode=None, title=None):
        # set the correct parameters depending on the kind
        if series and season and episode:
            url_series = self._search_url_title(series, 'series')
            url = self.server_url + 'cinemast/data/series/sb/{}/{}/{}/'.format(
                url_series, season, episode)
            page_link = self.server_url + 'subtitle/series/{}/{}/{}/'.format(
                url_series, season, episode)
        elif title:
            url_title = self._search_url_title(title, 'movie')
            url = self.server_url + 'cinemast/data/movie/sb/{}/'.format(
                url_title)
            page_link = self.server_url + 'subtitle/movie/{}/'.format(
                url_title)
        else:
            raise ValueError('One or more parameters are missing')

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(
                            subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug(
                                'Found additional release %r for subtitle %d',
                                release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases,
                                               release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(
                            language, hearing_impaired, page_link, series,
                            season, episode, title, subtitle_id, subtitle_key,
                            downloaded, [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()

    def list_subtitles(self, video, languages):
        series = None
        season = None
        episode = None
        title = video.title

        if isinstance(video, Episode):
            series = video.series
            season = video.season
            episode = video.episode

        return [
            s for s in self.query(series, season, episode, title)
            if s.language in languages
        ]

    def download_subtitle(self, subtitle):
        # download
        url = self.server_url + 'subtitle/download/{}/{}/'.format(
            subtitle.language.alpha2, subtitle.subtitle_id)
        params = {'v': subtitle.releases[0], 'key': subtitle.subtitle_key}
        r = self.session.get(url,
                             params=params,
                             headers={'Referer': subtitle.page_link},
                             timeout=10)
        r.raise_for_status()

        # open the zip
        with zipfile.ZipFile(io.BytesIO(r.content)) as zf:
            # remove some filenames from the namelist
            namelist = [n for n in zf.namelist() if not n.endswith('.txt')]
            if len(namelist) > 1:
                raise ProviderError('More than one file to unzip')

            subtitle.content = fix_line_ending(zf.read(namelist[0]))
Example #26
0
    def generateOptions(self, inputfile, original=None, force_transcode=False):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower(
        ) in self.video_codec and not force_transcode:
            vcodec = 'copy'
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            self.log.debug(
                "Overriding video pix_fmt. Codec cannot be copied because pix_fmt is not approved."
            )
            vcodec = self.video_codec[0]
            pix_fmt = self.pix_fmt[0]
            if self.video_profile:
                vprofile = self.video_profile[0]
        else:
            pix_fmt = None

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug(
                "Overriding video bitrate. Codec cannot be copied because video bitrate is too high."
            )
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug(
                "Video width is over the max width, it will be downsampled. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if '264' in info.video.codec.lower(
        ) and self.h264_level and info.video.video_level and (
                info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        self.log.info("Profile: %s." % info.video.profile)
        if self.video_profile and info.video.profile.lower().replace(
                " ", "") not in self.video_profile:
            self.log.debug(
                "Video profile is not supported. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vprofile = self.video_profile[0]
            if self.pix_fmt:
                pix_fmt = self.pix_fmt[0]
        else:
            vprofile = None

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata['language'].strip(
                ) == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'
            if (a.metadata['language'] == 'und' and self.adl) or (
                    self.awl and a.metadata['language'].lower() in self.awl):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info(
                "No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present."
            )

        audio_settings = {}
        blocked_audio_languages = []
        l = 0
        for a in info.audio:
            try:
                if a.metadata['language'].strip(
                ) == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'

            self.log.info("Audio detected for stream #%s: %s [%s]." %
                          (a.index, a.codec, a.metadata['language']))

            if self.output_extension in valid_tagging_extensions and a.codec.lower(
            ) == 'truehd' and self.ignore_truehd:  # Need to skip it early so that it flags the next track as default.
                self.log.info(
                    "MP4 containers do not support truehd audio, and converting it is inconsistent due to video/audio sync issues. Skipping stream %s as typically the 2nd audio track is the AC3 core of the truehd stream."
                    % a.index)
                continue

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata['language'] == 'und':
                self.log.debug(
                    "Undefined language detected, defaulting to [%s]." %
                    self.adl)
                a.metadata['language'] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            iosdata = None
            if self.awl is None or (a.metadata['language'].lower() in self.awl
                                    and a.metadata['language'].lower()
                                    not in blocked_audio_languages):
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS and a.audio_channels > 2:
                    iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (
                        self.audio_bitrate * 2)
                    self.log.info(
                        "Creating audio stream %s from source audio stream %s [iOS-audio]."
                        % (str(l), a.index))
                    self.log.debug("Audio codec: %s." % self.iOS[0])
                    self.log.debug("Channels: 2.")
                    self.log.debug("Filter: %s." % self.iOS_filter)
                    self.log.debug("Bitrate: %s." % iOSbitrate)
                    self.log.debug("Language: %s." % a.metadata['language'])
                    iosdata = {
                        'map': a.index,
                        'codec': self.iOS[0],
                        'channels': 2,
                        'bitrate': iOSbitrate,
                        'filter': self.iOS_filter,
                        'language': a.metadata['language'],
                        'disposition': 'none',
                    }
                    if not self.iOSLast:
                        audio_settings.update({l: iosdata})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info(
                    "Creating audio stream %s from source stream %s." %
                    (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug(
                        "Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio]."
                    )
                    acodec = 'copy' if a.codec in self.iOS else self.iOS[0]
                    audio_channels = a.audio_channels
                    afilter = self.iOS_filter
                    abitrate = a.audio_channels * 128 if (
                        a.audio_channels * self.audio_bitrate) > (
                            a.audio_channels * 128) else (a.audio_channels *
                                                          self.audio_bitrate)
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec.lower(
                    ) in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == 'copy':
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug(
                            "Attempting to set bitrate based on source stream bitrate."
                        )
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning(
                                "Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel."
                                % a.index)
                            abitrate = a.audio_channels * 256
                    afilter = self.audio_filter

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata['language'])
                self.log.debug("Filter: %s" % afilter)

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug(
                        "Not creating any additional iOS audio streams.")
                    self.iOS = False

                audio_settings.update({
                    l: {
                        'map': a.index,
                        'codec': acodec,
                        'channels': audio_channels,
                        'bitrate': abitrate,
                        'filter': afilter,
                        'language': a.metadata['language'],
                        'disposition': 'none',
                    }
                })

                if acodec == 'copy' and a.codec == 'aac' and self.aac_adtstoasc:
                    audio_settings[l]['bsf'] = 'aac_adtstoasc'
                l += 1

                # Add the iOS track last instead
                if self.iOSLast and iosdata:
                    audio_settings.update({l: iosdata})
                    l += 1

                if self.audio_copyoriginal and acodec != 'copy':
                    self.log.info(
                        "Adding copy of original audio track in format %s" %
                        a.codec)
                    audio_settings.update({
                        l: {
                            'map': a.index,
                            'codec': 'copy',
                            'language': a.metadata['language'],
                            'disposition': 'none',
                        }
                    })

                # Remove the language if we only want the first track from a given language
                if self.audio_first_language_track and self.awl:
                    try:
                        blocked_audio_languages.append(
                            a.metadata['language'].lower())
                        self.log.debug(
                            "Removing language from whitelist to prevent multiple tracks of the same: %s."
                            % a.metadata['language'])
                    except:
                        self.log.error(
                            "Unable to remove language %s from whitelist." %
                            a.metadata['language'])

        # Audio Default
        if len(audio_settings) > 0 and self.adl:
            try:
                default_track = [
                    x for x in audio_settings.values()
                    if x['language'] == self.adl
                ][0]
                default_track['disposition'] = 'default'
            except:
                audio_settings[0]['disposition'] = 'default'
        else:
            self.log.error("Audio language array is empty.")

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata['language'].strip(
                ) == "" or s.metadata['language'] is None:
                    s.metadata['language'] = 'und'
            except KeyError:
                s.metadata['language'] = 'und'

            self.log.info("Subtitle detected for stream #%s: %s [%s]." %
                          (s.index, s.codec, s.metadata['language']))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata['language'] == 'und':
                self.log.debug(
                    "Undefined language detected, defaulting to [%s]." %
                    self.sdl)
                s.metadata['language'] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata['language'].lower(
                ) in self.swl:
                    subtitle_settings.update({
                        l: {
                            'map': s.index,
                            'codec': self.scodec[0],
                            'language': s.metadata['language'],
                            'encoding': self.subencoding,
                            'disposition': 'none',
                            # 'forced': s.sub_forced,
                            # 'default': s.sub_default
                        }
                    })
                    self.log.info(
                        "Creating subtitle stream %s from source stream %s." %
                        (l, s.index))
                    l = l + 1
            elif s.codec.lower(
            ) not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata['language'].lower(
                ) in self.swl:
                    for codec in self.scodec:
                        ripsub = {
                            0: {
                                'map': s.index,
                                'codec': codec,
                                'language': s.metadata['language']
                            }
                        }
                        options = {
                            'format': codec,
                            'subtitle': ripsub,
                        }

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info(
                                "Wasn't able to determine subtitle file extension, defaulting to '.srt'."
                            )
                            extension = 'srt'

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(
                            inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(
                            output_dir, filename + "." +
                            s.metadata['language'] + forced + "." + extension)

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug(
                                "%s exists, appending %s to filename." %
                                (outputfile, i))
                            outputfile = os.path.join(
                                output_dir,
                                filename + "." + s.metadata['language'] +
                                forced + "." + str(i) + "." + extension)
                            i += 1
                        try:
                            self.log.info(
                                "Ripping %s subtitle from source stream %s into external file."
                                % (s.metadata['language'], s.index))
                            conv = Converter(self.FFMPEG_PATH,
                                             self.FFPROBE_PATH).convert(
                                                 inputfile,
                                                 outputfile,
                                                 options,
                                                 timeout=None)
                            for timecode in conv:
                                pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception(
                                "Unabled to create external subtitle file for stream %s."
                                % (s.index))

                        try:
                            os.chmod(outputfile, self.permissions
                                     )  # Set permissions of newly created file
                        except:
                            self.log.exception(
                                "Unable to set new file permissions.")

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error(
                    "No valid subtitle language specified, cannot download subtitles."
                )
        except:
            self.log.exception(
                "Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile),
                                              subtitles=True,
                                              embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles(
                    [video],
                    languages,
                    hearing_impaired=False,
                    providers=self.subproviders)
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info(
                        "Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs and not self.embedonlyinternalsubs:  # Don't bother if we're not embeddeding subtitles and external subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info(
                                "External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info(
                                    "Creating subtitle stream %s by importing %s."
                                    % (l, fname))

                                subtitle_settings.update({
                                    l: {
                                        'path': os.path.join(dirName, fname),
                                        'source': src,
                                        'map': 0,
                                        'codec': 'mov_text',
                                        'disposition': 'none',
                                        'language': lang
                                    }
                                })

                                self.log.debug("Path: %s." %
                                               os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(
                                    os.path.join(dirName, fname))

                            else:
                                self.log.info(
                                    "Ignoring %s external subtitle stream due to language %s."
                                    % (fname, lang))

        # Subtitle Default
        if len(subtitle_settings) > 0 and self.sdl:
            try:
                default_track = [
                    x for x in subtitle_settings.values()
                    if x['language'] == self.sdl
                ][0]
                default_track['disposition'] = 'default'
            except:
                subtitle_settings[0]['disposition'] = 'default'
        else:
            self.log.warning("Subtitle language array is empty.")

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate,
                'level': self.h264_level,
                'profile': vprofile,
                'pix_fmt': pix_fmt
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
            'preopts': [],
            'postopts': ['-threads', self.threads]
        }

        # If a CRF option is set, override the determine bitrate
        if self.vcrf:
            del options['video']['bitrate']
            options['video']['crf'] = self.vcrf

        if len(options['subtitle']) > 0:
            options['preopts'].append('-fix_sub_duration')

        if self.preopts:
            options['preopts'].extend(self.preopts)

        if self.postopts:
            options['postopts'].extend(self.postopts)

        if self.dxva2_decoder:  # DXVA2 will fallback to CPU decoding when it hits a file that it cannot handle, so we don't need to check if the file is supported.
            options['preopts'].extend(['-hwaccel', 'dxva2'])
        elif info.video.codec.lower() == "hevc" and self.hevc_qsv_decoder:
            options['preopts'].extend(['-vcodec', 'hevc_qsv'])
        elif vcodec == "h264qsv" and info.video.codec.lower(
        ) == "h264" and self.qsv_decoder and (info.video.video_level / 10) < 5:
            options['preopts'].extend(['-vcodec', 'h264_qsv'])

        if self.auto_crop:
            options['video']['mode'] = 'auto_crop'

        # Add width option
        if vwidth:
            options['video']['width'] = vwidth

        # HEVC Tagging for copied streams
        if info.video.codec.lower() in ['x265', 'h265', 'hevc'
                                        ] and vcodec == 'copy':
            options['postopts'].extend(['-tag:v', 'hvc1'])
            self.log.info("Tagging copied video stream as hvc1")

        self.options = options
        return options
Example #27
0
def rename_subs(path):
    filepaths = []
    sub_ext = ['.srt', '.sub', '.idx']
    vidfiles = core.list_media_files(path,
                                     media=True,
                                     audio=False,
                                     meta=False,
                                     archives=False)
    if not vidfiles or len(
            vidfiles
    ) > 1:  # If there is more than 1 video file, or no video files, we can't rename subs.
        return
    name = os.path.splitext(os.path.split(vidfiles[0])[1])[0]
    for directory, _, filenames in os.walk(path):
        for filename in filenames:
            filepaths.extend([os.path.join(directory, filename)])
    subfiles = [
        item for item in filepaths if os.path.splitext(item)[1] in sub_ext
    ]
    subfiles.sort(
    )  #This should sort subtitle names by language (alpha) and Number (where multiple)
    renamed = []
    for sub in subfiles:
        subname, ext = os.path.splitext(os.path.basename(sub))
        if name in subname:  # The sub file name already includes the video name.
            continue
        words = re.findall('[a-zA-Z]+',
                           str(subname))  # find whole words in string
        # parse the words for language descriptors.
        lan = None
        for word in words:
            try:
                if len(word) == 2:
                    lan = Language.fromalpha2(word.lower())
                elif len(word) == 3:
                    lan = Language(word.lower())
                elif len(word) > 3:
                    lan = Language.fromname(word.lower())
                if lan:
                    break
            except:  #if we didn't find a language, try next word.
                continue
        # rename the sub file as name.lan.ext
        if not lan:
            # could call ffprobe to parse the sub information and get language if lan unknown here.
            new_sub_name = name
        else:
            new_sub_name = '{name}.{lan}'.format(name=name, lan=str(lan))
        new_sub = os.path.join(directory,
                               new_sub_name)  # full path and name less ext
        if '{new_sub}{ext}'.format(
                new_sub=new_sub, ext=ext
        ) in renamed:  # If duplicate names, add unique number before ext.
            for i in range(1, len(renamed) + 1):
                if '{new_sub}.{i}{ext}'.format(new_sub=new_sub, i=i,
                                               ext=ext) in renamed:
                    continue
                new_sub = '{new_sub}.{i}'.format(new_sub=new_sub, i=i)
                break
        new_sub = '{new_sub}{ext}'.format(new_sub=new_sub,
                                          ext=ext)  # add extension now
        if os.path.isfile(new_sub):  # Don't copy over existing - final check.
            logger.debug(
                'Unable to rename sub file {old} as destination {new} already exists'
                .format(old=sub, new=new_sub))
            continue
        logger.debug('Renaming sub file from {old} to {new}'.format(
            old=sub, new=new_sub))
        renamed.append(new_sub)
        try:
            os.rename(sub, new_sub)
        except Exception as error:
            logger.error('Unable to rename sub file due to: {error}'.format(
                error=error))
    return
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = 'copy'
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug("Video width is over the max width, it will be downsampled. Video stream can no longer be copied.")
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if '264' in info.video.codec.lower() and self.h264_level and info.video.video_level and (info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'
            if (a.metadata['language'] == 'und' and self.adl) or (self.awl and a.metadata['language'].lower() in self.awl):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info("No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present.")

        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata['language']))

            if a.codec.lower() == 'truehd': # Need to skip it early so that it flags the next track as default.
                self.log.info( "MP4 containers do not support truehd audio, and converting it is inconsistent due to video/audio sync issues. Skipping stream %s as typically the 2nd audio track is the AC3 core of the truehd stream." % a.index )
                continue

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata['language'] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            iosdata = None

            if self.awl is None or a.metadata['language'].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS and a.audio_channels > 2:
                    vbrUsable = True if self.iOS[0] in valid_vbr_audio_codecs else False
                    iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (self.audio_bitrate * 2)
                    self.log.info("Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index))
                    self.log.debug("Audio codec: %s." % self.iOS[0])
                    self.log.debug("Channels: 2.")
                    self.log.debug("Filter: %s." % self.iOS_filter)
                    self.log.debug("Profile: %s." % self.iOS_profile)
                    self.log.debug("Bitrate: %s." % "Variable" if vbrUsable else iOSbitrate)
                    self.log.debug("Language: %s." % a.metadata['language'])
                    if l == 0:
                        disposition = 'default'
                        self.log.info("Audio track is number %s setting disposition to %s" % (str(l), disposition))
                    else:
                        disposition = 'none'
                        self.log.info("Audio track is number %s setting disposition to %s" % (str(l), disposition))
                    iosdata = {
                        'map': a.index,
                        'codec': self.iOS[0],
                        'channels': 2,
                        'bitrate': None if vbrUsable else iOSbitrate,
                        'vbr': self.avbr if vbrUsable else None,
                        'filter': self.iOS_filter,
                        'profile': self.iOS_profile,
                        'language': a.metadata['language'],
                        'disposition': disposition,
                    }
                    if not self.iOSLast:
                        audio_settings.update({l: iosdata})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug("Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio].")
                    acodec = 'copy' if a.codec in self.iOS else self.iOS[0]
                    audio_channels = a.audio_channels
                    afilter = self.iOS_filter
                    aprofile = self.iOS_profile
                    abitrate = a.audio_channels * 128 if (a.audio_channels * self.audio_bitrate) > (a.audio_channels * 128) else (a.audio_channels * self.audio_bitrate)
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == 'copy':
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning("Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel." % a.index)
                            abitrate = a.audio_channels * 256
                    afilter = self.audio_filter
                    aprofile = self.audio_profile

                vbrUsable = True if acodec in valid_vbr_audio_codecs else False
                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % "Variable" if vbrUsable else abitrate)
                self.log.debug("Language: %s" % a.metadata['language'])
                self.log.debug("Filter: %s" % afilter)
                self.log.debug("Profile: %s" % aprofile)

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                # Set first track as default disposition
                if l == 0:
                    disposition = 'default'
                    self.log.info("Audio Track is number %s setting disposition to %s" % (a.index, disposition))
                else:
                    disposition = 'none'
                    self.log.info("Audio Track is number %s setting disposition to %s" % (a.index, disposition))

                # If a VBR option is set, override the bitrate


                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': audio_channels,
                    'bitrate': None if vbrUsable else abitrate,
                    'vbr': self.avbr if vbrUsable else None,
                    'filter': afilter,
                    'profile': aprofile,
                    'language': a.metadata['language'],
                    'disposition': disposition,
                }})

                if acodec == 'copy' and a.codec == 'aac' and self.aac_adtstoasc:
                    audio_settings[l]['bsf'] = 'aac_adtstoasc'
                l += 1

                # Add the iOS track last instead
                if self.iOSLast and iosdata:
                    iosdata['disposition'] = 'none'
                    audio_settings.update({l: iosdata})
                    l += 1

                if self.audio_copyoriginal and acodec != 'copy':
                    self.log.info("Adding copy of original audio track in format %s" % a.codec)
                    audio_settings.update({l: {
                        'map': a.index,
                        'codec': 'copy',
                        'language': a.metadata['language'],
                        'disposition': 'none',
                    }})

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata['language'].strip() == "" or s.metadata['language'] is None:
                    s.metadata['language'] = 'und'
            except KeyError:
                s.metadata['language'] = 'und'

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata['language']))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata['language'] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': self.scodec[0],
                        'language': s.metadata['language'],
                        'encoding': self.subencoding,
                        # 'forced': s.sub_forced,
                        # 'default': s.sub_default
                    }})
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {0: {
                            'map': s.index,
                            'codec': codec,
                            'language': s.metadata['language']
                        }}
                        options = {
                            'format': codec,
                            'subtitle': ripsub,
                        }

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                            extension = 'srt'

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + extension)

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                            outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + str(i) + "." + extension)
                            i += 1
                        try:
                            self.log.info("Ripping %s subtitle from source stream %s into external file." % (s.metadata['language'], s.index))
                            conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                            for timecode in conv:
                                    pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error("No valid subtitle language specified, cannot download subtitles.")
        except:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs and not self.embedonlyinternalsubs:  # Don't bother if we're not embeddeding subtitles and external subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update({l: {
                                    'path': os.path.join(dirName, fname),
                                    'source': src,
                                    'map': 0,
                                    'codec': 'mov_text',
                                    'language': lang}})

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info("Ignoring %s external subtitle stream due to language %s." % (fname, lang))

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate,
                'level': self.h264_level
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
            'preopts': [],
            'postopts': ['-threads', self.threads]
        }

        # If a CRF option is set, override the determine bitrate
        if self.vcrf:
            del options['video']['bitrate']
            options['video']['crf'] = self.vcrf

        if len(options['subtitle']) > 0:
            options['preopts'].append('-fix_sub_duration')

        if self.preopts:
            options['preopts'].extend(self.preopts)

        if self.postopts:
            options['postopts'].extend(self.postopts)

        if self.dxva2_decoder:  # DXVA2 will fallback to CPU decoding when it hits a file that it cannot handle, so we don't need to check if the file is supported.
            options['preopts'].extend(['-hwaccel', 'dxva2'])
        elif info.video.codec.lower() == "hevc" and self.hevc_qsv_decoder:
            options['preopts'].extend(['-vcodec', 'hevc_qsv'])
        elif vcodec == "h264qsv" and info.video.codec.lower() == "h264" and self.qsv_decoder and (info.video.video_level / 10) < 5:
            options['preopts'].extend(['-vcodec', 'h264_qsv'])

        # Add width option
        if vwidth:
            options['video']['width'] = vwidth

        # Add pix_fmt
        if self.pix_fmt:
            options['video']['pix_fmt'] = self.pix_fmt[0]

        # HEVC Tagging for copied streams
        if info.video.codec.lower() in ['x265', 'h265', 'hevc'] and vcodec == 'copy':
            options['postopts'].extend(['-tag:v', 'hvc1'])
            self.log.info("Tagging copied video stream as hvc1")

        self.options = options
        return options
Example #29
0
class WizdomProvider(Provider):
    """Wizdom Provider."""
    languages = {Language.fromalpha2(l) for l in ['he']}
    server_url = 'wizdom.xyz'

    def __init__(self):
        self.session = None

    def initialize(self):
        self.session = Session()

    def terminate(self):
        self.session.close()

    @region.cache_on_arguments(expiration_time=SHOW_EXPIRATION_TIME)
    def _search_imdb_id(self, title, year, is_movie):
        """Search the IMDB ID for the given `title` and `year`.

        :param str title: title to search for.
        :param int year: year to search for (or 0 if not relevant).
        :param bool is_movie: If True, IMDB ID will be searched for in TMDB instead of Wizdom.
        :return: the IMDB ID for the given title and year (or None if not found).
        :rtype: str

        """
        # make the search
        logger.info('Searching IMDB ID for %r%r', title,
                    '' if not year else ' ({})'.format(year))
        category = 'movie' if is_movie else 'tv'
        title = title.replace('\'', '')
        # get TMDB ID first
        r = self.session.get(
            'https://api.tmdb.org/3/search/{}?api_key={}&query={}{}&language=en'
            .format(category, sickbeard.TMDB_API_KEY, title,
                    '' if not year else '&year={}'.format(year)))
        r.raise_for_status()
        tmdb_results = r.json().get('results')
        if tmdb_results:
            tmdb_id = tmdb_results[0].get('id')
            if tmdb_id:
                # get actual IMDB ID from TMDB
                r = self.session.get(
                    'https://api.tmdb.org/3/{}/{}{}?api_key={}&language=en'.
                    format(category, tmdb_id,
                           '' if is_movie else '/external_ids',
                           sickbeard.TMDB_API_KEY))
                r.raise_for_status()
                return str(r.json().get('imdb_id', '')) or None
        return None

    def query(self,
              title,
              season=None,
              episode=None,
              year=None,
              filename=None,
              imdb_id=None):
        # search for the IMDB ID if needed.
        is_movie = not (season and episode)
        imdb_id = imdb_id or self._search_imdb_id(title, year, is_movie)
        if not imdb_id:
            return {}

        # search
        logger.debug('Using IMDB ID %r', imdb_id)
        url = 'https://json.{}/{}.json'.format(self.server_url, imdb_id)
        page_link = 'https://{}/#/{}/{}'.format(
            self.server_url, 'movies' if is_movie else 'series', imdb_id)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        try:
            results = r.json()
        except ValueError:
            return {}

        # filter irrelevant results
        if not is_movie:
            results = results.get('subs', {}).get(str(season),
                                                  {}).get(str(episode), [])
        else:
            results = results.get('subs', [])

        # loop over results
        subtitles = {}
        for result in results:
            language = Language.fromalpha2('he')
            hearing_impaired = False
            subtitle_id = result['id']
            release = result['version']

            # add the release and increment downloaded count if we already have the subtitle
            if subtitle_id in subtitles:
                logger.debug('Found additional release %r for subtitle %d',
                             release, subtitle_id)
                bisect.insort_left(subtitles[subtitle_id].releases,
                                   release)  # deterministic order
                subtitles[subtitle_id].downloaded += 1
                continue

            # otherwise create it
            subtitle = WizdomSubtitle(language, hearing_impaired, page_link,
                                      title, season, episode, title, imdb_id,
                                      subtitle_id, [release])
            logger.debug('Found subtitle %r', subtitle)
            subtitles[subtitle_id] = subtitle

        return subtitles.values()

    def list_subtitles(self, video, languages):
        season = episode = None
        title = video.title
        year = video.year
        filename = video.name
        imdb_id = video.imdb_id

        if isinstance(video, Episode):
            title = video.series
            season = video.season
            episode = video.episode
            imdb_id = video.series_imdb_id

        return [
            s for s in self.query(title, season, episode, year, filename,
                                  imdb_id) if s.language in languages
        ]

    def download_subtitle(self, subtitle):
        # download
        url = 'https://zip.{}/{}.zip'.format(self.server_url,
                                             subtitle.subtitle_id)
        r = self.session.get(url,
                             headers={'Referer': subtitle.page_link},
                             timeout=10)
        r.raise_for_status()

        # open the zip
        with zipfile.ZipFile(io.BytesIO(r.content)) as zf:
            # remove some filenames from the namelist
            namelist = [
                n for n in zf.namelist()
                if os.path.splitext(n)[1] in ['.srt', '.sub']
            ]
            if len(namelist) > 1:
                raise ProviderError('More than one file to unzip')

            subtitle.content = fix_line_ending(zf.read(namelist[0]))
Example #30
0
class PodnapisiProvider(Provider):
    languages = ({Language('por', 'BR'), Language('srp', script='Latn')} |
                 {Language.fromalpha2(l) for l in language_converters['alpha2'].codes})
    video_types = (Episode, Movie)
    server_url = 'http://podnapisi.net/subtitles/'

    def initialize(self):
        self.session = Session()
        self.session.headers = {'User-Agent': 'Subliminal/%s' % get_version(__version__)}

    def terminate(self):
        self.session.close()

    def query(self, language, keyword, season=None, episode=None, year=None):
        # set parameters, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164#p212652
        params = {'sXML': 1, 'sL': str(language), 'sK': keyword}
        is_episode = False
        if season and episode:
            is_episode = True
            params['sTS'] = season
            params['sTE'] = episode
        if year:
            params['sY'] = year

        # loop over paginated results
        logger.info('Searching subtitles %r', params)
        subtitles = []
        pids = set()
        while True:
            # query the server
            xml = etree.fromstring(self.session.get(self.server_url + 'search/old', params=params, timeout=10).content)

            # exit if no results
            if not int(xml.find('pagination/results').text):
                logger.debug('No subtitles found')
                break

            # loop over subtitles
            for subtitle_xml in xml.findall('subtitle'):
                # read xml elements
                language = Language.fromietf(subtitle_xml.find('language').text)
                hearing_impaired = 'n' in (subtitle_xml.find('flags').text or '')
                page_link = subtitle_xml.find('url').text
                pid = subtitle_xml.find('pid').text
                releases = []
                if subtitle_xml.find('release').text:
                    for release in subtitle_xml.find('release').text.split():
                        releases.append(re.sub(r'\.+$', '', release))  # remove trailing dots
                title = subtitle_xml.find('title').text
                season = int(subtitle_xml.find('tvSeason').text)
                episode = int(subtitle_xml.find('tvEpisode').text)
                year = int(subtitle_xml.find('year').text)

                if is_episode:
                    subtitle = PodnapisiSubtitle(language, hearing_impaired, page_link, pid, releases, title,
                                                 season=season, episode=episode, year=year)
                else:
                    subtitle = PodnapisiSubtitle(language, hearing_impaired, page_link, pid, releases, title,
                                                 year=year)

                # ignore duplicates, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164&start=10#p213321
                if pid in pids:
                    continue

                logger.debug('Found subtitle %r', subtitle)
                subtitles.append(subtitle)
                pids.add(pid)

            # stop on last page
            if int(xml.find('pagination/current').text) >= int(xml.find('pagination/count').text):
                break

            # increment current page
            params['page'] = int(xml.find('pagination/current').text) + 1
            logger.debug('Getting page %d', params['page'])

        return subtitles

    def list_subtitles(self, video, languages):
        if isinstance(video, Episode):
            return [s for l in languages for s in self.query(l, video.series, season=video.season,
                                                             episode=video.episode, year=video.year)]
        elif isinstance(video, Movie):
            return [s for l in languages for s in self.query(l, video.title, year=video.year)]

    def download_subtitle(self, subtitle):
        # download as a zip
        logger.info('Downloading subtitle %r')
        r = self.session.get(self.server_url + subtitle.pid + '/download', params={'container': 'zip'}, timeout=10)
        r.raise_for_status()

        # open the zip
        with ZipFile(io.BytesIO(r.content)) as zf:
            if len(zf.namelist()) > 1:
                raise ProviderError('More than one file to unzip')

            subtitle.content = fix_line_ending(zf.read(zf.namelist()[0]))
Example #31
0
print(len(section))
fork, fork_params = auto_fork('SickBeard', 'tv')

if server_responding('http://127.0.0.1:5050'):
    print('CouchPotato Running')
if server_responding('http://127.0.0.1:7073'):
    print('SickBeard Running')
if server_responding('http://127.0.0.1:8181'):
    print('HeadPhones Running')
if server_responding('http://127.0.0.1:8085'):
    print('Gamez Running')
if server_responding('http://127.0.0.1:8090'):
    print('Mylar Running')

lan = 'pt'
lan = Language.fromalpha2(lan)
print(lan.alpha3)
vidName = '/volume1/Public/Movies/A Few Good Men/A Few Good Men(1992).mkv'
inputName = 'in.the.name.of.ben.hur.2016.bdrip.x264-rusted.nzb'
guess = guessit.guessit(inputName)
if guess:
    # Movie Title
    title = None
    if 'title' in guess:
        title = guess['title']
    # Movie Year
    year = None
    if 'year' in guess:
        year = guess['year']
    url = 'http://www.omdbapi.com'
    r = requests.get(url,
Example #32
0
fork, fork_params = autoFork('SickBeard', 'tv')

if server_responding("http://127.0.0.1:5050"):
    print "CouchPotato Running"
if server_responding("http://127.0.0.1:7073"):
    print "SickBeard Running"
if server_responding("http://127.0.0.1:8181"):
    print "HeadPhones Running"
if server_responding("http://127.0.0.1:8085"):
    print "Gamez Running"
if server_responding("http://127.0.0.1:8090"):
    print "Mylar Running"

from babelfish import Language
lan = 'pt'
lan = Language.fromalpha2(lan)
print lan.alpha3
vidName = "/volume1/Public/Movies/A Few Good Men/A Few Good Men(1992).mkv"
inputName = "in.the.name.of.ben.hur.2016.bdrip.x264-rusted.nzb"
guess = guessit.guessit(inputName)
if guess:
    # Movie Title
    title = None
    if 'title' in guess:
        title = guess['title']
    # Movie Year
    year = None
    if 'year' in guess:
        year = guess['year']
    url = "http://www.omdbapi.com"
    r = requests.get(url, params={'y': year, 't': title}, verify=False, timeout=(60, 300))
Example #33
0
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = 'copy'
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug("Video width is over the max width, it will be downsampled. Video stream can no longer be copied.")
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if self.h264_level and info.video.video_level and (info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'
            if (a.metadata['language'] == 'und' and self.adl) or (self.awl and a.metadata['language'].lower() in self.awl):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info("No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present.")

        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata['language']))

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata['language'] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.metadata['language'].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (self.audio_bitrate * 2)
                        self.log.info("Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index))
                        self.log.debug("Audio codec: %s." % self.iOS)
                        self.log.debug("Channels: 2.")
                        self.log.debug("Bitrate: %s." % iOSbitrate)
                        self.log.debug("Language: %s." % a.metadata['language'])
                        audio_settings.update({l: {
                            'map': a.index,
                            'codec': self.iOS,
                            'channels': 2,
                            'bitrate': iOSbitrate,
                            'language': a.metadata['language'],
                        }})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug("Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio].")
                    acodec = 'copy' if a.codec == self.iOS else self.iOS
                    audio_channels = a.audio_channels
                    abitrate = a.audio_channels * 128 if (a.audio_channels * self.audio_bitrate) > (a.audio_channels * 128) else (a.audio_channels * self.audio_bitrate)
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == 'copy':
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning("Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel." % a.index)
                            abitrate = a.audio_channels * 256

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata['language'])

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': audio_channels,
                    'bitrate': abitrate,
                    'language': a.metadata['language'],
                }})

                if acodec == 'copy' and a.codec == 'aac':
                    audio_settings[l]['bsf'] = 'aac_adtstoasc'
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata['language'].strip() == "" or s.metadata['language'] is None:
                    s.metadata['language'] = 'und'
            except KeyError:
                s.metadata['language'] = 'und'

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata['language']))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata['language'] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': self.scodec[0],
                        'language': s.metadata['language'],
                        'encoding': self.subencoding,
                        # 'forced': s.sub_forced,
                        # 'default': s.sub_default
                    }})
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {0: {
                            'map': s.index,
                            'codec': codec,
                            'language': s.metadata['language']
                        }}
                        options = {
                            'format': codec,
                            'subtitle': ripsub,
                        }

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                            extension = 'srt'

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + extension)

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                            outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + str(i) + "." + extension)
                            i += 1
                        try:
                            self.log.info("Ripping %s subtitle from source stream %s into external file." % (s.metadata['language'], s.index))
                            conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                            for timecode in conv:
                                    pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error("No valid subtitle language specified, cannot download subtitles.")
        except:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs:  # Don't bother if we're not embeddeding any subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update({l: {
                                    'path': os.path.join(dirName, fname),
                                    'source': src,
                                    'map': 0,
                                    'codec': 'mov_text',
                                    'language': lang}})

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info("Ignoring %s external subtitle stream due to language %s." % (fname, lang))

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate,
                'level': self.h264_level
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
            'preopts': ['-fix_sub_duration'],
            'postopts': ['-threads', self.threads]
        }

        # If using h264qsv, add the codec in front of the input for decoding
        if vcodec == "h264qsv" and info.video.codec.lower() == "h264" and self.qsv_decoder and (info.video.video_level / 10) < 5:
            options['preopts'].extend(['-vcodec', 'h264_qsv'])

        # Add width option
        if vwidth:
            options['video']['width'] = vwidth

        # Add pix_fmt
        if self.pix_fmt:
            options['video']['pix_fmt'] = self.pix_fmt[0]

        self.options = options
        return options
Example #34
0
class PodnapisiProvider(_PodnapisiProvider):
    languages = ({
        Language('por', 'BR'),
        Language('srp', script='Latn'),
        Language('srp', script='Cyrl')
    } | {Language.fromalpha2(l)
         for l in language_converters['alpha2'].codes})

    server_url = 'https://podnapisi.net/subtitles/'
    only_foreign = False
    subtitle_class = PodnapisiSubtitle
    hearing_impaired_verifiable = True

    def __init__(self, only_foreign=False):
        self.only_foreign = only_foreign

        if only_foreign:
            logger.info("Only searching for foreign/forced subtitles")

        super(PodnapisiProvider, self).__init__()

    def list_subtitles(self, video, languages):
        if video.is_special:
            logger.info("%s can't search for specials right now, skipping",
                        self)
            return []

        if isinstance(video, Episode):
            return [
                s for l in languages
                for s in self.query(l,
                                    video.series,
                                    season=video.season,
                                    episode=video.episode,
                                    year=video.year,
                                    only_foreign=self.only_foreign)
            ]
        elif isinstance(video, Movie):
            return [
                s for l in languages
                for s in self.query(l,
                                    video.title,
                                    year=video.year,
                                    only_foreign=self.only_foreign)
            ]

    def query(self,
              language,
              keyword,
              season=None,
              episode=None,
              year=None,
              only_foreign=False):
        search_language = str(language).lower()

        # sr-Cyrl specialcase
        if search_language == "sr-cyrl":
            search_language = "sr"

        # set parameters, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164#p212652
        params = {'sXML': 1, 'sL': search_language, 'sK': keyword}

        is_episode = False
        if season and episode:
            is_episode = True
            params['sTS'] = season
            params['sTE'] = episode

        if year:
            params['sY'] = year

        # loop over paginated results
        logger.info('Searching subtitles %r', params)
        subtitles = []
        pids = set()
        while True:
            # query the server
            content = None
            try:
                content = self.session.get(self.server_url + 'search/old',
                                           params=params,
                                           timeout=10).content
                xml = etree.fromstring(content)
            except XMLSyntaxError:
                logger.error("Wrong data returned: %r", content)
                break

            # exit if no results
            if not int(xml.find('pagination/results').text):
                logger.debug('No subtitles found')
                break

            # loop over subtitles
            for subtitle_xml in xml.findall('subtitle'):
                # read xml elements
                language = Language.fromietf(
                    subtitle_xml.find('language').text)
                hearing_impaired = 'n' in (subtitle_xml.find('flags').text
                                           or '')
                foreign = 'f' in (subtitle_xml.find('flags').text or '')
                if only_foreign and not foreign:
                    continue

                if not only_foreign and foreign:
                    continue

                page_link = subtitle_xml.find('url').text
                pid = subtitle_xml.find('pid').text
                releases = []
                if subtitle_xml.find('release').text:
                    for release in subtitle_xml.find('release').text.split():
                        releases.append(re.sub(
                            r'\.+$', '', release))  # remove trailing dots
                title = subtitle_xml.find('title').text
                season = int(subtitle_xml.find('tvSeason').text)
                episode = int(subtitle_xml.find('tvEpisode').text)
                year = int(subtitle_xml.find('year').text)

                if is_episode:
                    subtitle = self.subtitle_class(language,
                                                   hearing_impaired,
                                                   page_link,
                                                   pid,
                                                   releases,
                                                   title,
                                                   season=season,
                                                   episode=episode,
                                                   year=year)
                else:
                    subtitle = self.subtitle_class(language,
                                                   hearing_impaired,
                                                   page_link,
                                                   pid,
                                                   releases,
                                                   title,
                                                   year=year)

                # ignore duplicates, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164&start=10#p213321
                if pid in pids:
                    continue

                logger.debug('Found subtitle %r', subtitle)
                subtitles.append(subtitle)
                pids.add(pid)

            # stop on last page
            if int(xml.find('pagination/current').text) >= int(
                    xml.find('pagination/count').text):
                break

            # increment current page
            params['page'] = int(xml.find('pagination/current').text) + 1
            logger.debug('Getting page %d', params['page'])
            xml = None

        return subtitles
Example #35
0
def build_commands(file, new_dir, movie_name, bitbucket):
    if isinstance(file, string_types):
        input_file = file
        if 'concat:' in file:
            file = file.split('|')[0].replace('concat:', '')
        video_details, result = get_video_details(file)
        directory, name = os.path.split(file)
        name, ext = os.path.splitext(name)
        check = re.match('VTS_([0-9][0-9])_[0-9]+', name)
        if check and core.CONCAT:
            name = movie_name
        elif check:
            name = ('{0}.cd{1}'.format(movie_name, check.groups()[0]))
        elif core.CONCAT and re.match('(.+)[cC][dD][0-9]', name):
            name = re.sub('([ ._=:-]+[cC][dD][0-9])', '', name)
        if ext == core.VEXTENSION and new_dir == directory:  # we need to change the name to prevent overwriting itself.
            core.VEXTENSION = '-transcoded{ext}'.format(ext=core.VEXTENSION)  # adds '-transcoded.ext'
    else:
        img, data = next(iteritems(file))
        name = data['name']
        video_details, result = get_video_details(data['files'][0], img, bitbucket)
        input_file = '-'
        file = '-'

    newfile_path = os.path.normpath(os.path.join(new_dir, name) + core.VEXTENSION)

    map_cmd = []
    video_cmd = []
    audio_cmd = []
    audio_cmd2 = []
    sub_cmd = []
    meta_cmd = []
    other_cmd = []

    if not video_details or not video_details.get(
            'streams'):  # we couldn't read streams with ffprobe. Set defaults to try transcoding.
        video_streams = []
        audio_streams = []
        sub_streams = []

        map_cmd.extend(['-map', '0'])
        if core.VCODEC:
            video_cmd.extend(['-c:v', core.VCODEC])
            if core.VCODEC == 'libx264' and core.VPRESET:
                video_cmd.extend(['-pre', core.VPRESET])
        else:
            video_cmd.extend(['-c:v', 'copy'])
        if core.VFRAMERATE:
            video_cmd.extend(['-r', str(core.VFRAMERATE)])
        if core.VBITRATE:
            video_cmd.extend(['-b:v', str(core.VBITRATE)])
        if core.VRESOLUTION:
            video_cmd.extend(['-vf', 'scale={vres}'.format(vres=core.VRESOLUTION)])
        if core.VPRESET:
            video_cmd.extend(['-preset', core.VPRESET])
        if core.VCRF:
            video_cmd.extend(['-crf', str(core.VCRF)])
        if core.VLEVEL:
            video_cmd.extend(['-level', str(core.VLEVEL)])

        if core.ACODEC:
            audio_cmd.extend(['-c:a', core.ACODEC])
            if core.ACODEC in ['aac',
                               'dts']:  # Allow users to use the experimental AAC codec that's built into recent versions of ffmpeg
                audio_cmd.extend(['-strict', '-2'])
        else:
            audio_cmd.extend(['-c:a', 'copy'])
        if core.ACHANNELS:
            audio_cmd.extend(['-ac', str(core.ACHANNELS)])
        if core.ABITRATE:
            audio_cmd.extend(['-b:a', str(core.ABITRATE)])
        if core.OUTPUTQUALITYPERCENT:
            audio_cmd.extend(['-q:a', str(core.OUTPUTQUALITYPERCENT)])

        if core.SCODEC and core.ALLOWSUBS:
            sub_cmd.extend(['-c:s', core.SCODEC])
        elif core.ALLOWSUBS:  # Not every subtitle codec can be used for every video container format!
            sub_cmd.extend(['-c:s', 'copy'])
        else:  # http://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options
            sub_cmd.extend(['-sn'])  # Don't copy the subtitles over

        if core.OUTPUTFASTSTART:
            other_cmd.extend(['-movflags', '+faststart'])

    else:
        video_streams = [item for item in video_details['streams'] if item['codec_type'] == 'video']
        audio_streams = [item for item in video_details['streams'] if item['codec_type'] == 'audio']
        sub_streams = [item for item in video_details['streams'] if item['codec_type'] == 'subtitle']
        if core.VEXTENSION not in ['.mkv', '.mpegts']:
            sub_streams = [item for item in video_details['streams'] if
                           item['codec_type'] == 'subtitle' and item['codec_name'] != 'hdmv_pgs_subtitle' and item[
                               'codec_name'] != 'pgssub']

    for video in video_streams:
        codec = video['codec_name']
        fr = video.get('avg_frame_rate', 0)
        width = video.get('width', 0)
        height = video.get('height', 0)
        scale = core.VRESOLUTION
        if codec in core.VCODEC_ALLOW or not core.VCODEC:
            video_cmd.extend(['-c:v', 'copy'])
        else:
            video_cmd.extend(['-c:v', core.VCODEC])
        if core.VFRAMERATE and not (core.VFRAMERATE * 0.999 <= fr <= core.VFRAMERATE * 1.001):
            video_cmd.extend(['-r', str(core.VFRAMERATE)])
        if scale:
            w_scale = width / float(scale.split(':')[0])
            h_scale = height / float(scale.split(':')[1])
            if w_scale > h_scale:  # widescreen, Scale by width only.
                scale = '{width}:{height}'.format(
                    width=scale.split(':')[0],
                    height=int((height / w_scale) / 2) * 2,
                )
                if w_scale > 1:
                    video_cmd.extend(['-vf', 'scale={width}'.format(width=scale)])
            else:  # lower or matching ratio, scale by height only.
                scale = '{width}:{height}'.format(
                    width=int((width / h_scale) / 2) * 2,
                    height=scale.split(':')[1],
                )
                if h_scale > 1:
                    video_cmd.extend(['-vf', 'scale={height}'.format(height=scale)])
        if core.VBITRATE:
            video_cmd.extend(['-b:v', str(core.VBITRATE)])
        if core.VPRESET:
            video_cmd.extend(['-preset', core.VPRESET])
        if core.VCRF:
            video_cmd.extend(['-crf', str(core.VCRF)])
        if core.VLEVEL:
            video_cmd.extend(['-level', str(core.VLEVEL)])
        no_copy = ['-vf', '-r', '-crf', '-level', '-preset', '-b:v']
        if video_cmd[1] == 'copy' and any(i in video_cmd for i in no_copy):
            video_cmd[1] = core.VCODEC
        if core.VCODEC == 'copy':  # force copy. therefore ignore all other video transcoding.
            video_cmd = ['-c:v', 'copy']
        map_cmd.extend(['-map', '0:{index}'.format(index=video['index'])])
        break  # Only one video needed

    used_audio = 0
    a_mapped = []
    commentary = []
    if audio_streams:
        for i, val in reversed(list(enumerate(audio_streams))):
            try:
                if 'Commentary' in val.get('tags').get('title'):  # Split out commentry tracks.
                    commentary.append(val)
                    del audio_streams[i]
            except Exception:
                continue
        try:
            audio1 = [item for item in audio_streams if item['tags']['language'] == core.ALANGUAGE]
        except Exception:  # no language tags. Assume only 1 language.
            audio1 = audio_streams
        try:
            audio2 = [item for item in audio1 if item['codec_name'] in core.ACODEC_ALLOW]
        except Exception:
            audio2 = []
        try:
            audio3 = [item for item in audio_streams if item['tags']['language'] != core.ALANGUAGE]
        except Exception:
            audio3 = []
        try:
            audio4 = [item for item in audio3 if item['codec_name'] in core.ACODEC_ALLOW]
        except Exception:
            audio4 = []

        if audio2:  # right (or only) language and codec...
            map_cmd.extend(['-map', '0:{index}'.format(index=audio2[0]['index'])])
            a_mapped.extend([audio2[0]['index']])
            bitrate = int(float(audio2[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio2[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), 'copy'])
        elif audio1:  # right (or only) language, wrong codec.
            map_cmd.extend(['-map', '0:{index}'.format(index=audio1[0]['index'])])
            a_mapped.extend([audio1[0]['index']])
            bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio1[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), core.ACODEC if core.ACODEC else 'copy'])
        elif audio4:  # wrong language, right codec.
            map_cmd.extend(['-map', '0:{index}'.format(index=audio4[0]['index'])])
            a_mapped.extend([audio4[0]['index']])
            bitrate = int(float(audio4[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio4[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), 'copy'])
        elif audio3:  # wrong language, wrong codec. just pick the default audio track
            map_cmd.extend(['-map', '0:{index}'.format(index=audio3[0]['index'])])
            a_mapped.extend([audio3[0]['index']])
            bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
            channels = int(float(audio3[0].get('channels', 0)))
            audio_cmd.extend(['-c:a:{0}'.format(used_audio), core.ACODEC if core.ACODEC else 'copy'])

        if core.ACHANNELS and channels and channels > core.ACHANNELS:
            audio_cmd.extend(['-ac:a:{0}'.format(used_audio), str(core.ACHANNELS)])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if core.ABITRATE and not (core.ABITRATE * 0.9 < bitrate < core.ABITRATE * 1.1):
            audio_cmd.extend(['-b:a:{0}'.format(used_audio), str(core.ABITRATE)])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if core.OUTPUTQUALITYPERCENT:
            audio_cmd.extend(['-q:a:{0}'.format(used_audio), str(core.OUTPUTQUALITYPERCENT)])
            if audio_cmd[1] == 'copy':
                audio_cmd[1] = core.ACODEC
        if audio_cmd[1] in ['aac', 'dts']:
            audio_cmd[2:2] = ['-strict', '-2']

        if core.ACODEC2_ALLOW:
            used_audio += 1
            try:
                audio5 = [item for item in audio1 if item['codec_name'] in core.ACODEC2_ALLOW]
            except Exception:
                audio5 = []
            try:
                audio6 = [item for item in audio3 if item['codec_name'] in core.ACODEC2_ALLOW]
            except Exception:
                audio6 = []
            if audio5:  # right language and codec.
                map_cmd.extend(['-map', '0:{index}'.format(index=audio5[0]['index'])])
                a_mapped.extend([audio5[0]['index']])
                bitrate = int(float(audio5[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio5[0].get('channels', 0)))
                audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio1:  # right language wrong codec.
                map_cmd.extend(['-map', '0:{index}'.format(index=audio1[0]['index'])])
                a_mapped.extend([audio1[0]['index']])
                bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio1[0].get('channels', 0)))
                if core.ACODEC2:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), core.ACODEC2])
                else:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio6:  # wrong language, right codec
                map_cmd.extend(['-map', '0:{index}'.format(index=audio6[0]['index'])])
                a_mapped.extend([audio6[0]['index']])
                bitrate = int(float(audio6[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio6[0].get('channels', 0)))
                audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])
            elif audio3:  # wrong language, wrong codec just pick the default audio track
                map_cmd.extend(['-map', '0:{index}'.format(index=audio3[0]['index'])])
                a_mapped.extend([audio3[0]['index']])
                bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
                channels = int(float(audio3[0].get('channels', 0)))
                if core.ACODEC2:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), core.ACODEC2])
                else:
                    audio_cmd2.extend(['-c:a:{0}'.format(used_audio), 'copy'])

            if core.ACHANNELS2 and channels and channels > core.ACHANNELS2:
                audio_cmd2.extend(['-ac:a:{0}'.format(used_audio), str(core.ACHANNELS2)])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if core.ABITRATE2 and not (core.ABITRATE2 * 0.9 < bitrate < core.ABITRATE2 * 1.1):
                audio_cmd2.extend(['-b:a:{0}'.format(used_audio), str(core.ABITRATE2)])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if core.OUTPUTQUALITYPERCENT:
                audio_cmd2.extend(['-q:a:{0}'.format(used_audio), str(core.OUTPUTQUALITYPERCENT)])
                if audio_cmd2[1] == 'copy':
                    audio_cmd2[1] = core.ACODEC2
            if audio_cmd2[1] in ['aac', 'dts']:
                audio_cmd2[2:2] = ['-strict', '-2']

            if a_mapped[1] == a_mapped[0] and audio_cmd2[1:] == audio_cmd[1:]:  # check for duplicate output track.
                del map_cmd[-2:]
            else:
                audio_cmd.extend(audio_cmd2)

        if core.AINCLUDE and core.ACODEC3:
            audio_streams.extend(commentary)  # add commentry tracks back here.
            for audio in audio_streams:
                if audio['index'] in a_mapped:
                    continue
                used_audio += 1
                map_cmd.extend(['-map', '0:{index}'.format(index=audio['index'])])
                audio_cmd3 = []
                bitrate = int(float(audio.get('bit_rate', 0))) / 1000
                channels = int(float(audio.get('channels', 0)))
                if audio['codec_name'] in core.ACODEC3_ALLOW:
                    audio_cmd3.extend(['-c:a:{0}'.format(used_audio), 'copy'])
                else:
                    if core.ACODEC3:
                        audio_cmd3.extend(['-c:a:{0}'.format(used_audio), core.ACODEC3])
                    else:
                        audio_cmd3.extend(['-c:a:{0}'.format(used_audio), 'copy'])

                if core.ACHANNELS3 and channels and channels > core.ACHANNELS3:
                    audio_cmd3.extend(['-ac:a:{0}'.format(used_audio), str(core.ACHANNELS3)])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if core.ABITRATE3 and not (core.ABITRATE3 * 0.9 < bitrate < core.ABITRATE3 * 1.1):
                    audio_cmd3.extend(['-b:a:{0}'.format(used_audio), str(core.ABITRATE3)])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if core.OUTPUTQUALITYPERCENT > 0:
                    audio_cmd3.extend(['-q:a:{0}'.format(used_audio), str(core.OUTPUTQUALITYPERCENT)])
                    if audio_cmd3[1] == 'copy':
                        audio_cmd3[1] = core.ACODEC3
                if audio_cmd3[1] in ['aac', 'dts']:
                    audio_cmd3[2:2] = ['-strict', '-2']
                audio_cmd.extend(audio_cmd3)

    s_mapped = []
    burnt = 0
    n = 0
    for lan in core.SLANGUAGES:
        try:
            subs1 = [item for item in sub_streams if item['tags']['language'] == lan]
        except Exception:
            subs1 = []
        if core.BURN and not subs1 and not burnt and os.path.isfile(file):
            for subfile in get_subs(file):
                if lan in os.path.split(subfile)[1]:
                    video_cmd.extend(['-vf', 'subtitles={subs}'.format(subs=subfile)])
                    burnt = 1
        for sub in subs1:
            if core.BURN and not burnt and os.path.isfile(input_file):
                subloc = 0
                for index in range(len(sub_streams)):
                    if sub_streams[index]['index'] == sub['index']:
                        subloc = index
                        break
                video_cmd.extend(['-vf', 'subtitles={sub}:si={loc}'.format(sub=input_file, loc=subloc)])
                burnt = 1
            if not core.ALLOWSUBS:
                break
            if sub['codec_name'] in ['dvd_subtitle', 'VobSub'] and core.SCODEC == 'mov_text':  # We can't convert these.
                continue
            map_cmd.extend(['-map', '0:{index}'.format(index=sub['index'])])
            s_mapped.extend([sub['index']])

    if core.SINCLUDE:
        for sub in sub_streams:
            if not core.ALLOWSUBS:
                break
            if sub['index'] in s_mapped:
                continue
            if sub['codec_name'] in ['dvd_subtitle', 'VobSub'] and core.SCODEC == 'mov_text':  # We can't convert these.
                continue
            map_cmd.extend(['-map', '0:{index}'.format(index=sub['index'])])
            s_mapped.extend([sub['index']])

    if core.OUTPUTFASTSTART:
        other_cmd.extend(['-movflags', '+faststart'])

    command = [core.FFMPEG, '-loglevel', 'warning']

    if core.HWACCEL:
        command.extend(['-hwaccel', 'auto'])
    if core.GENERALOPTS:
        command.extend(core.GENERALOPTS)

    command.extend(['-i', input_file])

    if core.SEMBED and os.path.isfile(file):
        for subfile in get_subs(file):
            sub_details, result = get_video_details(subfile)
            if not sub_details or not sub_details.get('streams'):
                continue
            if core.SCODEC == 'mov_text':
                subcode = [stream['codec_name'] for stream in sub_details['streams']]
                if set(subcode).intersection(['dvd_subtitle', 'VobSub']):  # We can't convert these.
                    continue
            command.extend(['-i', subfile])
            lan = os.path.splitext(os.path.splitext(subfile)[0])[1][1:].split('-')[0]
            lan = text_type(lan)
            metlan = None
            try:
                if len(lan) == 3:
                    metlan = Language(lan)
                if len(lan) == 2:
                    metlan = Language.fromalpha2(lan)
            except Exception:
                pass
            if metlan:
                meta_cmd.extend(['-metadata:s:s:{x}'.format(x=len(s_mapped) + n),
                                 'language={lang}'.format(lang=metlan.alpha3)])
            n += 1
            map_cmd.extend(['-map', '{x}:0'.format(x=n)])

    if not core.ALLOWSUBS or (not s_mapped and not n):
        sub_cmd.extend(['-sn'])
    else:
        if core.SCODEC:
            sub_cmd.extend(['-c:s', core.SCODEC])
        else:
            sub_cmd.extend(['-c:s', 'copy'])

    command.extend(map_cmd)
    command.extend(video_cmd)
    command.extend(audio_cmd)
    command.extend(sub_cmd)
    command.extend(meta_cmd)
    command.extend(other_cmd)
    command.append(newfile_path)
    if platform.system() != 'Windows':
        command = core.NICENESS + command
    return command
    def generateOptions(self, inputfile, original=None):    
        #Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)
       
        #Video stream
        print "Video codec detected: " + info.video.codec
        vcodec = 'copy' if info.video.codec in self.video_codec else self.video_codec[0]

        #Audio streams
        audio_settings = {}
        l = 0
        for a in info.audio:
            print "Audio stream detected: " + a.codec + " " + a.language + " [Stream " + str(a.index) + "]"
            # Set undefined language to default language if specified
            if self.adl is not None and a.language == 'und':
                print "Undefined language detected, defaulting to " + self.adl
                a.language = self.adl
            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.language in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        print "Creating dual audio channels for iOS compatability for this stream"
                        audio_settings.update({l: {
                            'map': a.index,
                            'codec': self.iOS,
                            'channels': 2,
                            'bitrate': 256,
                            'language': a.language,
                        }})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                if self.iOS and a.audio_channels == 2:
                    acodec = 'copy' if a.codec == 'aac' else self.iOS
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec in self.audio_codec else self.audio_codec[0]

                # Bitrate calculations/overrides
                if self.audio_bitrate is None or self.audio_bitrate > (a.audio_channels * 256):
                    abitrate = 256 * a.audio_channels
                else:
                    abitrate = self.audio_bitrate

                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': a.audio_channels,
                    'bitrate': abitrate,
                    'language': a.language,
                }})
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        for s in info.subtitle:
            print "Subtitle stream detected: " + s.codec + " " + s.language + " [Stream " + str(s.index) + "]"

            # Set undefined language to default language if specified
            if self.sdl is not None and s.language == 'und':
                s.language = self.sdl
            # Make sure its not an image based codec
            if s.codec not in bad_subtitle_codecs and self.embedsubs:
                
                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.language in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': 'mov_text',
                        'language': s.language
                        #'forced': s.sub_forced,
                        #'default': s.sub_default
                    }})
                    l = l + 1
            else:
                if self.swl is None or s.language in self.swl:
                    ripsub = {1: {
                        'map': s.index,
                        'codec': 'srt',
                        'language': s.language
                    }}
                    options = {
                        'format': 'srt',
                        'subtitle': ripsub,
                    }
                    input_dir, filename, input_extension = self.parseFile(inputfile)
                    output_dir = input_dir if self.output_dir is None else self.output_dir
                    outputfile = os.path.join(output_dir, filename + "." + s.language + ".srt")
                    
                    i = 2
                    while os.path.isfile(outputfile):
                        outputfile = os.path.join(output_dir, filename + "." + s.language + "." + str(i) + ".srt")
                        i += i
                    print "Ripping " + s.language + " subtitle from file"
                    conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                    for timecode in conv:
                            pass

                    try:
                        print outputfile + " created"
                    except:
                        print "File created"

        # External subtitle import

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        if self.swl:
            for alpha3 in self.swl:
                languages.add(Language(alpha3))
        elif self.sdl:
            languages.add(Language(self.sdl))
        else:
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            print "Attempting to download subtitles, please wait"

            try:
                subliminal.cache_region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True, original=original)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                subliminal.save_subtitles(subtitles)
            except Exception as e:
                print e
                print "Unable to download subtitle"

        src = 1  # FFMPEG input source number
        for dirName, subdirList, fileList in os.walk(input_dir):
            for fname in fileList:
                subname, subextension = os.path.splitext(fname)
                # Watch for appropriate file extension
                if subextension[1:] in valid_subtitle_extensions:
                    x, lang = os.path.splitext(subname)
                    lang = lang[1:]
                    # Using bablefish to convert a 2 language code to a 3 language code
                    if len(lang) is 2:
                        try:
                            babel = Language.fromalpha2(lang)
                            lang = babel.alpha3
                        except:
                            pass
                    # If subtitle file name and input video name are the same, proceed
                    if x == filename and self.embedsubs:
                        print "External subtitle file detected, language " + lang
                        if self.swl is None or lang in self.swl:
                            print "Importing %s subtitle stream" % (fname)
                            subtitle_settings.update({l: {
                                'path': os.path.join(dirName, fname),
                                'source': src,
                                'map': 0,
                                'codec': 'mov_text',
                                'language': lang,
                                }})
                            l = l + 1
                            src = src + 1
                            self.deletesubs.add(os.path.join(dirName, fname))
                        else:
                            print "Ignoring %s external subtitle stream due to language: %s" % (fname, lang)

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': info.format.bitrate
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
        }
        self.options = options
        return options
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except Exception:
            raise
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = "copy"
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            self.log.debug(
                "Overriding video pix_fmt. Codec cannot be copied because pix_fmt is not approved."
            )
            vcodec = self.video_codec[0]
            pix_fmt = self.pix_fmt[0]
            if self.video_profile:
                vprofile = self.video_profile[0]
        else:
            pix_fmt = None

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug(
                "Overriding video bitrate. Codec cannot be copied because video bitrate is too high."
            )
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug(
                "Video width is over the max width, it will be downsampled. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if (
            "264" in info.video.codec.lower()
            and self.h264_level
            and info.video.video_level
            and (info.video.video_level / 10 > self.h264_level)
        ):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        self.log.info("Profile: %s." % info.video.profile)
        if (
            self.video_profile
            and info.video.profile.lower().replace(" ", "") not in self.video_profile
        ):
            self.log.debug(
                "Video profile is not supported. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vprofile = self.video_profile[0]
            if self.pix_fmt:
                pix_fmt = self.pix_fmt[0]
        else:
            vprofile = None

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if (
                    a.metadata["language"].strip() == ""
                    or a.metadata["language"] is None
                ):
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"
            if (a.metadata["language"] == "und" and self.adl) or (
                self.awl and a.metadata["language"].lower() in self.awl
            ):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info(
                "No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present."
            )

        audio_settings = {}
        blocked_audio_languages = []
        l = 0
        for a in info.audio:
            try:
                if (
                    a.metadata["language"].strip() == ""
                    or a.metadata["language"] is None
                ):
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"

            self.log.info(
                "Audio detected for stream #%s: %s [%s]."
                % (a.index, a.codec, a.metadata["language"])
            )

            if (
                self.output_extension in valid_tagging_extensions
                and a.codec.lower() == "truehd"
            ):  # Need to skip it early so that it flags the next track as default.
                self.log.info(
                    "MP4 containers do not support truehd audio, and converting it is inconsistent due to video/audio sync issues. Skipping stream %s as typically the 2nd audio track is the AC3 core of the truehd stream."
                    % a.index
                )
                continue

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata["language"] == "und":
                self.log.debug(
                    "Undefined language detected, defaulting to [%s]." % self.adl
                )
                a.metadata["language"] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            iosdata = None
            if self.awl is None or (
                a.metadata["language"].lower() in self.awl
                and a.metadata["language"].lower() not in blocked_audio_languages
            ):
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS and a.audio_channels > 2:
                    iOSbitrate = (
                        256
                        if (self.audio_bitrate * 2) > 256
                        else (self.audio_bitrate * 2)
                    )
                    self.log.info(
                        "Creating audio stream %s from source audio stream %s [iOS-audio]."
                        % (str(l), a.index)
                    )
                    self.log.debug("Audio codec: %s." % self.iOS[0])
                    self.log.debug("Channels: 2.")
                    self.log.debug("Filter: %s." % self.iOS_filter)
                    self.log.debug("Bitrate: %s." % iOSbitrate)
                    self.log.debug("Language: %s." % a.metadata["language"])
                    if l == 0:
                        disposition = "default"
                        self.log.info(
                            "Audio track is number %s setting disposition to %s"
                            % (str(l), disposition)
                        )
                    else:
                        disposition = "none"
                        self.log.info(
                            "Audio track is number %s setting disposition to %s"
                            % (str(l), disposition)
                        )
                    iosdata = {
                        "map": a.index,
                        "codec": self.iOS[0],
                        "channels": 2,
                        "bitrate": iOSbitrate,
                        "filter": self.iOS_filter,
                        "language": a.metadata["language"],
                        "disposition": disposition,
                    }
                    if not self.iOSLast:
                        audio_settings.update({l: iosdata})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info(
                    "Creating audio stream %s from source stream %s."
                    % (str(l), a.index)
                )
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug(
                        "Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio]."
                    )
                    acodec = "copy" if a.codec in self.iOS else self.iOS[0]
                    audio_channels = a.audio_channels
                    afilter = self.iOS_filter
                    abitrate = (
                        a.audio_channels * 128
                        if (a.audio_channels * self.audio_bitrate)
                        > (a.audio_channels * 128)
                        else (a.audio_channels * self.audio_bitrate)
                    )
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = (
                        "copy"
                        if a.codec.lower() in self.audio_codec
                        else self.audio_codec[0]
                    )
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == "copy":
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug(
                            "Attempting to set bitrate based on source stream bitrate."
                        )
                        try:
                            abitrate = a.bitrate / 1000
                        except Exception:
                            self.log.warning(
                                "Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel."
                                % a.index
                            )
                            abitrate = a.audio_channels * 256
                    afilter = self.audio_filter

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata["language"])
                self.log.debug("Filter: %s" % afilter)

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                # Set first track as default disposition
                if l == 0:
                    disposition = "default"
                    self.log.info(
                        "Audio Track is number %s setting disposition to %s"
                        % (a.index, disposition)
                    )
                else:
                    disposition = "none"
                    self.log.info(
                        "Audio Track is number %s setting disposition to %s"
                        % (a.index, disposition)
                    )

                audio_settings.update(
                    {
                        l: {
                            "map": a.index,
                            "codec": acodec,
                            "channels": audio_channels,
                            "bitrate": abitrate,
                            "filter": afilter,
                            "language": a.metadata["language"],
                            "disposition": disposition,
                        }
                    }
                )

                if acodec == "copy" and a.codec == "aac" and self.aac_adtstoasc:
                    audio_settings[l]["bsf"] = "aac_adtstoasc"
                l += 1

                # Add the iOS track last instead
                if self.iOSLast and iosdata:
                    iosdata["disposition"] = "none"
                    audio_settings.update({l: iosdata})
                    l += 1

                if self.audio_copyoriginal and acodec != "copy":
                    self.log.info(
                        "Adding copy of original audio track in format %s" % a.codec
                    )
                    audio_settings.update(
                        {
                            l: {
                                "map": a.index,
                                "codec": "copy",
                                "language": a.metadata["language"],
                                "disposition": "none",
                            }
                        }
                    )

                # Remove the language if we only want the first track from a given language
                if self.audio_first_language_track and self.awl:
                    try:
                        blocked_audio_languages.append(a.metadata["language"].lower())
                        self.log.debug(
                            "Removing language from whitelist to prevent multiple tracks of the same: %s."
                            % a.metadata["language"]
                        )
                    except Exception:
                        self.log.error(
                            "Unable to remove language %s from whitelist."
                            % a.metadata["language"]
                        )

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if (
                    s.metadata["language"].strip() == ""
                    or s.metadata["language"] is None
                ):
                    s.metadata["language"] = "und"
            except KeyError:
                s.metadata["language"] = "und"

            self.log.info(
                "Subtitle detected for stream #%s: %s [%s]."
                % (s.index, s.codec, s.metadata["language"])
            )

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata["language"] == "und":
                self.log.debug(
                    "Undefined language detected, defaulting to [%s]." % self.sdl
                )
                s.metadata["language"] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    subtitle_settings.update(
                        {
                            l: {
                                "map": s.index,
                                "codec": self.scodec[0],
                                "language": s.metadata["language"],
                                "encoding": self.subencoding,
                                # 'forced': s.sub_forced,
                                # 'default': s.sub_default
                            }
                        }
                    )
                    self.log.info(
                        "Creating subtitle stream %s from source stream %s."
                        % (l, s.index)
                    )
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {
                            0: {
                                "map": s.index,
                                "codec": codec,
                                "language": s.metadata["language"],
                            }
                        }
                        options = {"format": codec, "subtitle": ripsub}

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except Exception:
                            self.log.info(
                                "Wasn't able to determine subtitle file extension, defaulting to '.srt'."
                            )
                            extension = "srt"

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = (
                            input_dir if self.output_dir is None else self.output_dir
                        )
                        outputfile = os.path.join(
                            output_dir,
                            filename
                            + "."
                            + s.metadata["language"]
                            + forced
                            + "."
                            + extension,
                        )

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug(
                                "%s exists, appending %s to filename." % (outputfile, i)
                            )
                            outputfile = os.path.join(
                                output_dir,
                                filename
                                + "."
                                + s.metadata["language"]
                                + forced
                                + "."
                                + str(i)
                                + "."
                                + extension,
                            )
                            i += 1
                        try:
                            self.log.info(
                                "Ripping %s subtitle from source stream %s into external file."
                                % (s.metadata["language"], s.index)
                            )
                            conv = Converter(
                                self.FFMPEG_PATH, self.FFPROBE_PATH
                            ).convert(inputfile, outputfile, options, timeout=None)
                            for timecode in conv:
                                pass

                            self.log.info("%s created." % outputfile)
                        except Exception:
                            self.log.exception(
                                "Unabled to create external subtitle file for stream %s."
                                % (s.index)
                            )

                        try:
                            os.chmod(
                                outputfile, self.permissions
                            )  # Set permissions of newly created file
                        except Exception:
                            self.log.exception("Unable to set new file permissions.")

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error(
                    "No valid subtitle language specified, cannot download subtitles."
                )
        except Exception:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal

            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure("dogpile.cache.memory")
            except Exception:
                pass

            try:
                video = subliminal.scan_video(
                    os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True
                )
                subtitles = subliminal.download_best_subtitles(
                    [video],
                    languages,
                    hearing_impaired=False,
                    providers=self.subproviders,
                )
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except Exception:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if (
            self.embedsubs and not self.embedonlyinternalsubs
        ):  # Don't bother if we're not embeddeding subtitles and external subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except Exception:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info(
                                    "Creating subtitle stream %s by importing %s."
                                    % (l, fname)
                                )

                                subtitle_settings.update(
                                    {
                                        l: {
                                            "path": os.path.join(dirName, fname),
                                            "source": src,
                                            "map": 0,
                                            "codec": "mov_text",
                                            "language": lang,
                                        }
                                    }
                                )

                                self.log.debug(
                                    "Path: %s." % os.path.join(dirName, fname)
                                )
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info(
                                    "Ignoring %s external subtitle stream due to language %s."
                                    % (fname, lang)
                                )

        # Collect all options
        options = {
            "format": self.output_format,
            "video": {
                "codec": vcodec,
                "map": info.video.index,
                "bitrate": vbitrate,
                "level": self.h264_level,
                "profile": vprofile,
                "pix_fmt": pix_fmt,
            },
            "audio": audio_settings,
            "subtitle": subtitle_settings,
            "preopts": [],
            "postopts": ["-threads", self.threads],
        }

        # If a CRF option is set, override the determine bitrate
        if self.vcrf:
            del options["video"]["bitrate"]
            options["video"]["crf"] = self.vcrf

        if len(options["subtitle"]) > 0:
            options["preopts"].append("-fix_sub_duration")

        if self.preopts:
            options["preopts"].extend(self.preopts)

        if self.postopts:
            options["postopts"].extend(self.postopts)

        if (
            self.dxva2_decoder
        ):  # DXVA2 will fallback to CPU decoding when it hits a file that it cannot handle, so we don't need to check if the file is supported.
            options["preopts"].extend(["-hwaccel", "dxva2"])
        elif info.video.codec.lower() == "hevc" and self.hevc_qsv_decoder:
            options["preopts"].extend(["-vcodec", "hevc_qsv"])
        elif (
            vcodec == "h264qsv"
            and info.video.codec.lower() == "h264"
            and self.qsv_decoder
            and (info.video.video_level / 10) < 5
        ):
            options["preopts"].extend(["-vcodec", "h264_qsv"])

        # Add width option
        if vwidth:
            options["video"]["width"] = vwidth

        # HEVC Tagging for copied streams
        if info.video.codec.lower() in ["x265", "h265", "hevc"] and vcodec == "copy":
            options["postopts"].extend(["-tag:v", "hvc1"])
            self.log.info("Tagging copied video stream as hvc1")

        self.options = options
        return options
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = "copy"
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug(
                "Video width is over the max width, it will be downsampled. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if self.h264_level and info.video.video_level and (info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata["language"].strip() == "" or a.metadata["language"] is None:
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"
            if (a.metadata["language"] == "und" and self.adl) or (
                self.awl and a.metadata["language"].lower() in self.awl
            ):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info(
                "No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present."
            )

        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata["language"].strip() == "" or a.metadata["language"] is None:
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata["language"]))

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata["language"] == "und":
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata["language"] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.metadata["language"].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (self.audio_bitrate * 2)
                        self.log.info(
                            "Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index)
                        )
                        self.log.debug("Audio codec: %s." % self.iOS)
                        self.log.debug("Channels: 2.")
                        self.log.debug("Bitrate: %s." % iOSbitrate)
                        self.log.debug("Language: %s." % a.metadata["language"])
                        audio_settings.update(
                            {
                                l: {
                                    "map": a.index,
                                    "codec": self.iOS,
                                    "channels": 2,
                                    "bitrate": iOSbitrate,
                                    "language": a.metadata["language"],
                                }
                            }
                        )
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug(
                        "Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio]."
                    )
                    acodec = "copy" if a.codec == self.iOS else self.iOS
                    audio_channels = a.audio_channels
                    abitrate = (
                        a.audio_channels * 128
                        if (a.audio_channels * self.audio_bitrate) > (a.audio_channels * 128)
                        else (a.audio_channels * self.audio_bitrate)
                    )
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = "copy" if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == "copy":
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning(
                                "Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel."
                                % a.index
                            )
                            abitrate = a.audio_channels * 256

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata["language"])

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                audio_settings.update(
                    {
                        l: {
                            "map": a.index,
                            "codec": acodec,
                            "channels": audio_channels,
                            "bitrate": abitrate,
                            "language": a.metadata["language"],
                        }
                    }
                )

                if acodec == "copy" and a.codec == "aac":
                    audio_settings[l]["bsf"] = "aac_adtstoasc"
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata["language"].strip() == "" or s.metadata["language"] is None:
                    s.metadata["language"] = "und"
            except KeyError:
                s.metadata["language"] = "und"

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata["language"]))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata["language"] == "und":
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata["language"] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    subtitle_settings.update(
                        {
                            l: {
                                "map": s.index,
                                "codec": self.scodec[0],
                                "language": s.metadata["language"],
                                "encoding": self.subencoding,
                                # 'forced': s.sub_forced,
                                # 'default': s.sub_default
                            }
                        }
                    )
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {0: {"map": s.index, "codec": codec, "language": s.metadata["language"]}}
                        options = {"format": codec, "subtitle": ripsub}

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                            extension = "srt"

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(
                            output_dir, filename + "." + s.metadata["language"] + forced + "." + extension
                        )

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                            outputfile = os.path.join(
                                output_dir,
                                filename + "." + s.metadata["language"] + forced + "." + str(i) + "." + extension,
                            )
                            i += 1
                        try:
                            self.log.info(
                                "Ripping %s subtitle from source stream %s into external file."
                                % (s.metadata["language"], s.index)
                            )
                            conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(
                                inputfile, outputfile, options, timeout=None
                            )
                            for timecode in conv:
                                pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error("No valid subtitle language specified, cannot download subtitles.")
        except:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal

            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure("dogpile.cache.memory")
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles(
                    [video], languages, hearing_impaired=False, providers=self.subproviders
                )
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs:  # Don't bother if we're not embeddeding any subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update(
                                    {
                                        l: {
                                            "path": os.path.join(dirName, fname),
                                            "source": src,
                                            "map": 0,
                                            "codec": "mov_text",
                                            "language": lang,
                                        }
                                    }
                                )

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info(
                                    "Ignoring %s external subtitle stream due to language %s." % (fname, lang)
                                )

        # Collect all options
        options = {
            "format": self.output_format,
            "video": {"codec": vcodec, "map": info.video.index, "bitrate": vbitrate, "level": self.h264_level},
            "audio": audio_settings,
            "subtitle": subtitle_settings,
            "preopts": ["-fix_sub_duration"],
            "postopts": ["-threads", self.threads],
        }

        # If using h264qsv, add the codec in front of the input for decoding
        if (
            vcodec == "h264qsv"
            and info.video.codec.lower() == "h264"
            and self.qsv_decoder
            and (info.video.video_level / 10) < 5
        ):
            options["preopts"].extend(["-vcodec", "h264_qsv"])

        # Add width option
        if vwidth:
            options["video"]["width"] = vwidth

        # Add pix_fmt
        if self.pix_fmt:
            options["video"]["pix_fmt"] = self.pix_fmt[0]

        self.options = options
        return options
    def generateOptions(self, inputfile, original=None):
        #Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        #Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s" % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate/1000

        vcodec = 'copy' if info.video.codec.lower() in self.video_codec else self.video_codec[0]
        vbitrate = vbr

        self.log.info("Pix Fmt: %s" % info.video.pix_fmt)
        if self.pix_fmt and self.pix_fmt.lower() != info.video.pix_fmt.lower():
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug("Video width is over the max width, it will be downsampled. Video stream can no longer be copied.")
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if self.h264_level and info.video.video_level and info.video.video_level/10 > self.h264_level:
            self.log.info("Video level %0.1f." % info.video.video_level)
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s" % vcodec)
        self.log.debug("Video bitrate: %s" % vbitrate)

        #Audio streams
        self.log.info("Reading audio streams.")
        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata['language']))

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata['language'] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.metadata['language'].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        self.log.info("Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index))
                        self.log.debug("Audio codec: %s." % self.iOS)
                        self.log.debug("Channels: 2.")
                        self.log.debug("Bitrate: 256.")
                        self.log.debug("Language: %s" % a.metadata['language'])
                        audio_settings.update({l: {
                            'map': a.index,
                            'codec': self.iOS,
                            'channels': 2,
                            'bitrate': 256,
                            'language': a.metadata['language'],
                        }})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug("Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio].")
                    acodec = 'copy' if a.codec == self.iOS else self.iOS
                    audio_channels = a.audio_channels
                    abitrate = a.audio_channels * 128
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == 'copy':
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate/1000
                        except:
                            self.log.warning("Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel." % a.index)
                            abitrate = a.audio_channels * 256

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata['language'])

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': audio_channels,
                    'bitrate': abitrate,
                    'language': a.metadata['language'],
                }})
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata['language'].strip() == "" or s.metadata['language'] is None:
                    s.metadata['language'] = 'und'
            except KeyError:
                s.metadata['language'] = 'und'

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata['language']))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata['language'] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': self.scodec,
                        'language': s.metadata['language']
                        #'forced': s.sub_forced,
                        #'default': s.sub_default
                    }})
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    ripsub = {0: {
                        'map': s.index,
                        'codec': self.scodec,
                        'language': s.metadata['language']
                    }}
                    options = {
                        'format': self.scodec,
                        'subtitle': ripsub,
                    }

                    try:
                        extension = subtitle_codec_extensions[self.scodec]
                    except:
                        self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                        extension = 'srt'

                    input_dir, filename, input_extension = self.parseFile(inputfile)
                    output_dir = input_dir if self.output_dir is None else self.output_dir
                    outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + "." + extension)

                    i = 2
                    while os.path.isfile(outputfile):
                        self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                        outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + "." + str(i) + "." + extension)
                        i += 1
                    try:
                        self.log.info("Ripping %s subtitle from source stream %s into external file." % (s.metadata['language'], s.index))
                        conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                        for timecode in conv:
                                pass

                        self.log.info("%s created." % outputfile)
                    except:
                        self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        if self.swl:
            for alpha3 in self.swl:
                languages.add(Language(alpha3))
        elif self.sdl:
            languages.add(Language(self.sdl))
        else:
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            self.log.info("Attempting to download subtitles.")
            try:
                subliminal.cache_region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile.decode(sys.getfilesystemencoding())), subtitles=True, embedded_subtitles=True, original=original)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                subliminal.save_subtitles(subtitles)
            except Exception as e:
                self.log.debug("Unable to download subtitles.", exc_info=True)

        # External subtitle import
        if self.embedsubs: #Don't bother if we're not embeddeding any subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update({l: {
                                    'path': os.path.join(dirName, fname),
                                    'source': src,
                                    'map': 0,
                                    'codec': 'mov_text',
                                    'language': lang,
                                    }})

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info("Ignoring %s external subtitle stream due to language %s." % (fname, lang))

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate,
                'level': self.h264_level
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
        }

        # Add width option
        if vwidth: options['video']['width'] = vwidth
        # Add pix_fmt
        if self.pix_fmt: options['video']['pix_fmt'] = self.pix_fmt

        self.options = options
        return options
Example #40
0
class SubsCenterProvider(Provider):
    """SubsCenter Provider."""
    languages = {Language.fromalpha2(l) for l in ['he']}
    server_url = 'http://www.subscenter.info/he/'

    def __init__(self, username=None, password=None):
        if username is not None and password is None or username is None and password is not None:
            raise ConfigurationError('Username and password must be specified')

        self.session = None
        self.username = username
        self.password = password
        self.logged_in = False

    def initialize(self):
        self.session = Session()
        self.session.headers['User-Agent'] = 'Subliminal/{}'.format(
            __short_version__)

        # login
        if self.username is not None and self.password is not None:
            logger.debug('Logging in')
            url = self.server_url + 'subscenter/accounts/login/'

            # retrieve CSRF token
            self.session.get(url)
            csrf_token = self.session.cookies['csrftoken']

            # actual login
            data = {
                'username': self.username,
                'password': self.password,
                'csrfmiddlewaretoken': csrf_token
            }
            r = self.session.post(url, data, allow_redirects=False, timeout=10)

            if r.status_code != 302:
                raise AuthenticationError(self.username)

            logger.info('Logged in')
            self.logged_in = True

    def terminate(self):
        # logout
        if self.logged_in:
            logger.info('Logging out')
            r = self.session.get(self.server_url +
                                 'subscenter/accounts/logout/',
                                 timeout=10)
            r.raise_for_status()
            logger.info('Logged out')
            self.logged_in = False

        self.session.close()

    @region.cache_on_arguments(expiration_time=SHOW_EXPIRATION_TIME)
    def _search_url_titles(self, title):
        """Search the URL titles by kind for the given `title`.

        :param str title: title to search for.
        :return: the URL titles by kind.
        :rtype: collections.defaultdict

        """
        # make the search
        logger.info('Searching title name for %r', title)
        r = self.session.get(self.server_url + 'subtitle/search/',
                             params={'q': title},
                             timeout=10)
        r.raise_for_status()

        # check for redirections
        if r.history and all([h.status_code == 302 for h in r.history]):
            logger.debug('Redirected to the subtitles page')
            links = [r.url]
        else:
            # get the suggestions (if needed)
            soup = ParserBeautifulSoup(r.content, ['lxml', 'html.parser'])
            links = [
                link.attrs['href']
                for link in soup.select('#processes div.generalWindowTop a')
            ]
            logger.debug('Found %d suggestions', len(links))

        url_titles = defaultdict(list)
        for link in links:
            parts = link.split('/')
            url_titles[parts[-3]].append(parts[-2])

        return url_titles

    def query(self, title, season=None, episode=None):
        # search for the url title
        url_titles = self._search_url_titles(title)

        # episode
        if season and episode:
            if 'series' not in url_titles:
                logger.error('No URL title found for series %r', title)
                return []
            url_title = url_titles['series'][0]
            logger.debug('Using series title %r', url_title)
            url = self.server_url + 'cst/data/series/sb/{}/{}/{}/'.format(
                url_title, season, episode)
            page_link = self.server_url + 'subtitle/series/{}/{}/{}/'.format(
                url_title, season, episode)
        else:
            if 'movie' not in url_titles:
                logger.error('No URL title found for movie %r', title)
                return []
            url_title = url_titles['movie'][0]
            logger.debug('Using movie title %r', url_title)
            url = self.server_url + 'cst/data/movie/sb/{}/'.format(url_title)
            page_link = self.server_url + 'subtitle/movie/{}/'.format(
                url_title)

        # get the list of subtitles
        logger.debug('Getting the list of subtitles')
        r = self.session.get(url)
        r.raise_for_status()
        results = json.loads(r.text)

        # loop over results
        subtitles = {}
        for language_code, language_data in results.items():
            for quality_data in language_data.values():
                for quality, subtitles_data in quality_data.items():
                    for subtitle_item in subtitles_data.values():
                        # read the item
                        language = Language.fromalpha2(language_code)
                        hearing_impaired = bool(
                            subtitle_item['hearing_impaired'])
                        subtitle_id = subtitle_item['id']
                        subtitle_key = subtitle_item['key']
                        subtitle_version = subtitle_item['h_version']
                        downloaded = subtitle_item['downloaded']
                        release = subtitle_item['subtitle_version']

                        # add the release and increment downloaded count if we already have the subtitle
                        if subtitle_id in subtitles:
                            logger.debug(
                                'Found additional release %r for subtitle %d',
                                release, subtitle_id)
                            bisect.insort_left(subtitles[subtitle_id].releases,
                                               release)  # deterministic order
                            subtitles[subtitle_id].downloaded += downloaded
                            continue

                        # otherwise create it
                        subtitle = SubsCenterSubtitle(
                            language, hearing_impaired, page_link, title,
                            season, episode, title, subtitle_id, subtitle_key,
                            subtitle_version, downloaded, [release])
                        logger.debug('Found subtitle %r', subtitle)
                        subtitles[subtitle_id] = subtitle

        return subtitles.values()

    def list_subtitles(self, video, languages):
        season = episode = None
        title = video.title

        if isinstance(video, Episode):
            title = video.series
            season = video.season
            episode = video.episode

        return [
            s for s in self.query(title, season, episode)
            if s.language in languages
        ]

    def download_subtitle(self, subtitle):
        # download
        url = self.server_url + 'subtitle/download/{}/{}/'.format(
            subtitle.language.alpha2, subtitle.subtitle_id)
        params = {'v': subtitle.subtitle_version, 'key': subtitle.subtitle_key}
        r = self.session.get(url,
                             params=params,
                             headers={'Referer': subtitle.page_link},
                             timeout=10)
        r.raise_for_status()

        # open the zip
        try:
            with zipfile.ZipFile(io.BytesIO(r.content)) as zf:
                # remove some filenames from the namelist
                namelist = [n for n in zf.namelist() if not n.endswith('.txt')]
                if len(namelist) > 1:
                    raise ProviderError('More than one file to unzip')

                subtitle.content = fix_line_ending(zf.read(namelist[0]))
        except zipfile.BadZipfile:
            # if no zip file was retrieved, daily downloads limit has exceeded
            raise ProviderError('Daily limit exceeded')
Example #41
0
class ArgenteamProvider(Provider):
    provider_name = 'argenteam'
    language = Language.fromalpha2('es')
    languages = {language}
    video_types = (Episode, )
    server_url = "http://argenteam.net/api/v1/"
    subtitle_class = ArgenteamSubtitle

    def __init__(self):
        self.session = None

    def initialize(self):
        self.session = Session()
        self.session.headers['User-Agent'] = self.user_agent

    def terminate(self):
        self.session.close()

    @region.cache_on_arguments(expiration_time=EPISODE_EXPIRATION_TIME,
                               should_cache_fn=lambda value: value)
    def search_episode_id(self, series, season, episode):
        """Search the episode id from the `series`, `season` and `episode`.

        :param str series: series of the episode.
        :param int season: season of the episode.
        :param int episode: episode number.
        :return: the episode id, if any.
        :rtype: int or None

        """
        # make the search
        query = '%s S%#02dE%#02d' % (series, season, episode)
        logger.info('Searching episode id for %r', query)
        r = self.session.get(self.server_url + 'search',
                             params={'q': query},
                             timeout=10)
        r.raise_for_status()
        results = json.loads(r.text)
        if results['total'] == 1:
            return results['results'][0]['id']

        logger.error('No episode id found for %r', series)

    def query(self, series, season, episode):
        episode_id = self.search_episode_id(series, season, episode)
        if episode_id is None:
            return []

        response = self.session.get(self.server_url + 'episode',
                                    params={'id': episode_id},
                                    timeout=10)
        response.raise_for_status()
        content = json.loads(response.text)
        subtitles = []
        for r in content['releases']:
            for s in r['subtitles']:
                subtitle = self.subtitle_class(self.language, s['uri'], series,
                                               season, episode, r['team'],
                                               r['tags'])
                logger.debug('Found subtitle %r', subtitle)
                subtitles.append(subtitle)

        return subtitles

    def list_subtitles(self, video, languages):
        titles = [video.series] + video.alternative_series
        for title in titles:
            subs = self.query(title, video.season, video.episode)
            if subs:
                return subs

        return []

    def download_subtitle(self, subtitle):
        # download as a zip
        logger.info('Downloading subtitle %r', subtitle)
        r = self.session.get(subtitle.download_link, timeout=10)
        r.raise_for_status()

        # open the zip
        with ZipFile(io.BytesIO(r.content)) as zf:
            if len(zf.namelist()) > 1:
                raise ProviderError('More than one file to unzip')

            subtitle.content = fix_line_ending(zf.read(zf.namelist()[0]))
Example #42
0
    def generateOptions(self, inputfile, original=None):
        #Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        #Video stream
        print "Video codec detected: " + info.video.codec
        vcodec = 'copy' if info.video.codec in self.video_codec else self.video_codec[
            0]
        if self.video_bitrate is not None:
            vbitrate = self.video_bitrate
        else:
            vbitrate = info.format.bitrate

        #Audio streams
        audio_settings = {}
        l = 0
        for a in info.audio:
            print "Audio stream detected: " + a.codec + " " + a.language + " [Stream " + str(
                a.index) + "]"
            # Set undefined language to default language if specified
            if self.adl is not None and a.language == 'und':
                print "Undefined language detected, defaulting to " + self.adl
                a.language = self.adl
            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.language in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        print "Creating dual audio channels for iOS compatability for this stream"
                        audio_settings.update({
                            l: {
                                'map': a.index,
                                'codec': 'aac',
                                'channels': 2,
                                'bitrate': 256,
                                'language': a.language,
                            }
                        })
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                if self.iOS and a.audio_channels <= 2:
                    acodec = 'copy' if a.codec == 'aac' else self.iOS
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec in self.audio_codec else self.audio_codec[
                        0]

                # Audio channel adjustments
                if self.maxchannels and a.audio_channels > self.maxchannels:
                    audio_channels = self.maxchannels
                    if acodec == 'copy':
                        acodec = self.audio_codec[0]
                else:
                    audio_channels = a.audio_channels

                # Bitrate calculations/overrides
                if self.audio_bitrate is None or self.audio_bitrate > (
                        a.audio_channels * 256):
                    abitrate = 256 * audio_channels
                else:
                    abitrate = self.audio_bitrate

                audio_settings.update({
                    l: {
                        'map': a.index,
                        'codec': acodec,
                        'channels': audio_channels,
                        'bitrate': abitrate,
                        'language': a.language,
                    }
                })
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        for s in info.subtitle:
            print "Subtitle stream detected: " + s.codec + " " + s.language + " [Stream " + str(
                s.index) + "]"

            # Set undefined language to default language if specified
            if self.sdl is not None and s.language == 'und':
                s.language = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.language in self.swl:
                    subtitle_settings.update({
                        l: {
                            'map': s.index,
                            'codec': 'mov_text',
                            'language': s.language
                            #'forced': s.sub_forced,
                            #'default': s.sub_default
                        }
                    })
                    l = l + 1
            elif s.codec.lower(
            ) not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.language in self.swl:
                    ripsub = {
                        1: {
                            'map': s.index,
                            'codec': 'srt',
                            'language': s.language
                        }
                    }
                    options = {
                        'format': 'srt',
                        'subtitle': ripsub,
                    }
                    input_dir, filename, input_extension = self.parseFile(
                        inputfile)
                    output_dir = input_dir if self.output_dir is None else self.output_dir
                    outputfile = os.path.join(
                        output_dir, filename + "." + s.language + ".srt")

                    i = 2
                    while os.path.isfile(outputfile):
                        outputfile = os.path.join(
                            output_dir, filename + "." + s.language + "." +
                            str(i) + ".srt")
                        i += i
                    print "Ripping " + s.language + " subtitle from file"
                    conv = Converter(self.FFMPEG_PATH,
                                     self.FFPROBE_PATH).convert(inputfile,
                                                                outputfile,
                                                                options,
                                                                timeout=None)
                    for timecode in conv:
                        pass

                    try:
                        print outputfile + " created"
                    except:
                        print "File created"

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        if self.swl:
            for alpha3 in self.swl:
                languages.add(Language(alpha3))
        elif self.sdl:
            languages.add(Language(self.sdl))
        else:
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            print "Attempting to download subtitles, please wait"

            try:
                subliminal.cache_region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile),
                                              subtitles=True,
                                              embedded_subtitles=True,
                                              original=original)
                subtitles = subliminal.download_best_subtitles(
                    [video],
                    languages,
                    hearing_impaired=False,
                    providers=self.subproviders)
                subliminal.save_subtitles(subtitles)
            except Exception as e:
                print e
                print "Unable to download subtitle"

        # External subtitle import
        if self.embedsubs:  #Don't bother if we're not embeddeding any subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            print "External subtitle file detected, language " + lang
                            if self.swl is None or lang in self.swl:
                                print "Importing %s subtitle stream" % (fname)
                                subtitle_settings.update({
                                    l: {
                                        'path': os.path.join(dirName, fname),
                                        'source': src,
                                        'map': 0,
                                        'codec': 'mov_text',
                                        'language': lang,
                                    }
                                })
                                l = l + 1
                                src = src + 1
                                self.deletesubs.add(
                                    os.path.join(dirName, fname))
                            else:
                                print "Ignoring %s external subtitle stream due to language: %s" % (
                                    fname, lang)

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
        }
        self.options = options
        return options
Example #43
0
def test_get_matches_no_match(episodes):
    subtitle = ArgenteamSubtitle(Language.fromalpha2('es'), None,
                                 'Marvels Agents Of S.H.I.E.L.D.', 2, 6,
                                 'KILLERS', '1080p')
    matches = subtitle.get_matches(episodes['house_of_cards_us_s06e01'])
    assert matches == set()