Esempio n. 1
0
    def _get_season_subtitles(self, series_id, season, sub_format):
        params = {
            'apikey': self.apikey,
            'series_id': series_id,
            'q': 'Stagione %{}'.format(season),
            'version': sub_format
        }
        r = self.session.get(self.server_url + 'subtitles/search',
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = etree.fromstring(r.content)

        if int(root.find('data/count').text) == 0:
            logger.warning(
                'Subtitles for season not found, try with rip suffix')

            params['version'] = sub_format + 'rip'
            r = self.session.get(self.server_url + 'subtitles/search',
                                 params=params,
                                 timeout=30)
            r.raise_for_status()
            root = etree.fromstring(r.content)
            if int(root.find('data/count').text) == 0:
                logger.warning('Subtitles for season not found')
                return []

        subs = []
        # Looking for subtitles in first page
        season_re = re.compile('.*?stagione 0*?{}.*'.format(season))
        for subtitle in root.findall('data/subtitles/subtitle'):
            if season_re.match(subtitle.find('name').text.lower()):
                logger.debug('Found season zip id %d - %r - %r',
                             int(subtitle.find('id').text),
                             subtitle.find('name').text,
                             subtitle.find('version').text)

                content = self._download_zip(int(subtitle.find('id').text))
                if not is_zipfile(io.BytesIO(content)):  # pragma: no cover
                    if 'limite di download' in content:
                        raise DownloadLimitExceeded()
                    else:
                        raise ConfigurationError(
                            'Not a zip file: {!r}'.format(content))

                with ZipFile(io.BytesIO(content)) as zf:
                    episode_re = re.compile('s(\d{1,2})e(\d{1,2})')
                    for index, name in enumerate(zf.namelist()):
                        match = episode_re.search(name)
                        if not match:  # pragma: no cover
                            logger.debug('Cannot decode subtitle %r', name)
                        else:
                            sub = ItaSASubtitle(
                                int(subtitle.find('id').text),
                                subtitle.find('show_name').text,
                                int(match.group(1)), int(match.group(2)), None,
                                None, None, name)
                            sub.content = fix_line_ending(zf.read(name))
                            subs.append(sub)

        return subs
Esempio n. 2
0
    def query(self, series, season, episode, source, resolution, country=None):

        # To make queries you need to be logged in
        if not self.logged_in:  # pragma: no cover
            raise ConfigurationError("Cannot query if not logged in")

        # get the show id
        show_id = self.get_show_id(series, country)
        if show_id is None:
            logger.error("No show id found for %r ", series)
            return []

        # get the page of the season of the show
        logger.info(
            "Getting the subtitle of show id %d, season %d episode %d, source %r",
            show_id, season, episode, source)
        subtitles = []

        # Default source is SDTV
        if not source or source.lower() == "hdtv":
            if resolution in ("1080i", "1080p", "720p"):
                sub_source = resolution
            else:
                sub_source = "normale"
        else:
            sub_source = source.lower()

        # Look for year
        params = {"apikey": self.apikey}
        r = self.session.get(self.server_url + "shows/" + str(show_id),
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = ElementTree.fromstring(r.content)

        year = root.find("data/show/started").text
        if year:
            year = int(year.split("-", 1)[0])
        tvdb_id = root.find("data/show/id_tvdb").text
        if tvdb_id:
            tvdb_id = int(tvdb_id)

        params = {
            "apikey": self.apikey,
            "show_id": show_id,
            "q": "%dx%02d" % (season, episode),
            "version": sub_source
        }
        r = self.session.get(self.server_url + "subtitles/search",
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = ElementTree.fromstring(r.content)

        if int(root.find("data/count").text) == 0:
            logger.warning("Subtitles not found,  try with rip suffix")

            params["version"] = sub_source + "rip"
            r = self.session.get(self.server_url + "subtitles/search",
                                 params=params,
                                 timeout=30)
            r.raise_for_status()
            root = ElementTree.fromstring(r.content)
            if int(root.find("data/count").text) == 0:
                logger.warning("Subtitles not found, go season mode")

                # If no subtitle are found for single episode try to download all season zip
                subs = self._get_season_subtitles(show_id, season, sub_source)
                if subs:
                    for subtitle in subs:
                        subtitle.source = source
                        subtitle.year = year
                        subtitle.tvdb_id = tvdb_id

                    return subs
                else:
                    return []

        # Looking for subtitles in first page
        for subtitle in root.findall("data/subtitles/subtitle"):
            if "%dx%02d" % (season,
                            episode) in subtitle.find("name").text.lower():

                logger.debug("Found subtitle id %d - %r - %r",
                             int(subtitle.find("id").text),
                             subtitle.find("name").text,
                             subtitle.find("version").text)

                sub = ItaSASubtitle(int(subtitle.find("id").text),
                                    subtitle.find("show_name").text, season,
                                    episode, source, year, tvdb_id,
                                    subtitle.find("name").text)

                subtitles.append(sub)

        # Not in the first page of result try next (if any)
        next_page = root.find("data/next")
        while next_page.text is not None:  # pragma: no cover

            r = self.session.get(next_page.text, timeout=30)
            r.raise_for_status()
            root = ElementTree.fromstring(r.content)

            # logger.info('Loading subtitles page %r', root.data.page.text)

            # Looking for show in following pages
            for subtitle in root.findall("data/subtitles/subtitle"):
                if "%dx%02d" % (season,
                                episode) in subtitle.find("name").text.lower():

                    logger.debug("Found subtitle id %d - %r - %r",
                                 int(subtitle.find("id").text),
                                 subtitle.find("name").text,
                                 subtitle.find("version").text)

                    sub = ItaSASubtitle(int(subtitle.find("id").text),
                                        subtitle.find("show_name").text,
                                        season, episode, source, year, tvdb_id,
                                        subtitle.find("name").text)

                    subtitles.append(sub)

            next_page = root.find("data/next")

        # Download the subs found, can be more than one in zip
        additional_subs = []
        for sub in subtitles:

            # open the zip
            content = self._download_zip(sub.sub_id)
            if not is_zipfile(io.BytesIO(content)):  # pragma: no cover
                if "limite di download" in content:
                    raise DownloadLimitExceeded()
                else:
                    raise ConfigurationError("Not a zip file: %r" % content)

            with ZipFile(io.BytesIO(content)) as zf:
                if len(zf.namelist()) > 1:  # pragma: no cover

                    for index, name in enumerate(zf.namelist()):

                        if index == 0:
                            # First element
                            sub.content = fix_line_ending(zf.read(name))
                            sub.full_data = name
                        else:
                            add_sub = copy.deepcopy(sub)
                            add_sub.content = fix_line_ending(zf.read(name))
                            add_sub.full_data = name
                            additional_subs.append(add_sub)
                else:
                    sub.content = fix_line_ending(zf.read(zf.namelist()[0]))
                    sub.full_data = zf.namelist()[0]

        return subtitles + additional_subs
Esempio n. 3
0
    def query(self,
              series,
              season,
              episode,
              video_format,
              resolution,
              country=None):

        # To make queries you need to be logged in
        if not self.logged_in:  # pragma: no cover
            raise ConfigurationError('Cannot query if not logged in')

        # get the show id
        show_id = self.get_show_id(series, country)
        if show_id is None:
            logger.error('No show id found for %r ', series)
            return []

        # get the page of the season of the show
        logger.info(
            'Getting the subtitle of show id %d, season %d episode %d, format %r',
            show_id, season, episode, video_format)
        subtitles = []

        # Default format is SDTV
        if not video_format or video_format.lower() == 'hdtv':
            if resolution in ('1080i', '1080p', '720p'):
                sub_format = resolution
            else:
                sub_format = 'normale'
        else:
            sub_format = video_format.lower()

        # Look for year
        params = {'apikey': self.apikey}
        r = self.session.get(self.server_url + 'shows/' + str(show_id),
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = etree.fromstring(r.content)

        year = root.find('data/show/started').text
        if year:
            year = int(year.split('-', 1)[0])
        tvdb_id = root.find('data/show/id_tvdb').text
        if tvdb_id:
            tvdb_id = int(tvdb_id)

        params = {
            'apikey': self.apikey,
            'show_id': show_id,
            'q': '%dx%02d' % (season, episode),
            'version': sub_format
        }
        r = self.session.get(self.server_url + 'subtitles/search',
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = etree.fromstring(r.content)

        if int(root.find('data/count').text) == 0:
            logger.warning('Subtitles not found,  try with rip suffix')

            params['version'] = sub_format + 'rip'
            r = self.session.get(self.server_url + 'subtitles/search',
                                 params=params,
                                 timeout=30)
            r.raise_for_status()
            root = etree.fromstring(r.content)
            if int(root.find('data/count').text) == 0:
                logger.warning('Subtitles not found, go season mode')

                # If no subtitle are found for single episode try to download all season zip
                subs = self._get_season_subtitles(show_id, season, sub_format)
                if subs:
                    for subtitle in subs:
                        subtitle.format = video_format
                        subtitle.year = year
                        subtitle.tvdb_id = tvdb_id

                    return subs
                else:
                    return []

        # Looking for subtitles in first page
        for subtitle in root.findall('data/subtitles/subtitle'):
            if '%dx%02d' % (season,
                            episode) in subtitle.find('name').text.lower():

                logger.debug('Found subtitle id %d - %r - %r',
                             int(subtitle.find('id').text),
                             subtitle.find('name').text,
                             subtitle.find('version').text)

                sub = ItaSASubtitle(int(subtitle.find('id').text),
                                    subtitle.find('show_name').text, season,
                                    episode, video_format, year, tvdb_id,
                                    subtitle.find('name').text)

                subtitles.append(sub)

        # Not in the first page of result try next (if any)
        next_page = root.find('data/next')
        while next_page.text is not None:  # pragma: no cover

            r = self.session.get(next_page.text, timeout=30)
            r.raise_for_status()
            root = etree.fromstring(r.content)

            logger.info('Loading subtitles page %r', root.data.page.text)

            # Looking for show in following pages
            for subtitle in root.findall('data/subtitles/subtitle'):
                if '%dx%02d' % (season,
                                episode) in subtitle.find('name').text.lower():

                    logger.debug('Found subtitle id %d - %r - %r',
                                 int(subtitle.find('id').text),
                                 subtitle.find('name').text,
                                 subtitle.find('version').text)

                    sub = ItaSASubtitle(int(subtitle.find('id').text),
                                        subtitle.find('show_name').text,
                                        season, episode, video_format, year,
                                        tvdb_id,
                                        subtitle.find('name').text)

                    subtitles.append(sub)

            next_page = root.find('data/next')

        # Download the subs found, can be more than one in zip
        additional_subs = []
        for sub in subtitles:

            # open the zip
            content = self._download_zip(sub.sub_id)
            if not is_zipfile(io.BytesIO(content)):  # pragma: no cover
                if 'limite di download' in content:
                    raise DownloadLimitExceeded()
                else:
                    raise ConfigurationError('Not a zip file: %r' % content)

            with ZipFile(io.BytesIO(content)) as zf:
                if len(zf.namelist()) > 1:  # pragma: no cover

                    for index, name in enumerate(zf.namelist()):

                        if index == 0:
                            # First element
                            sub.content = fix_line_ending(zf.read(name))
                            sub.full_data = name
                        else:
                            add_sub = copy.deepcopy(sub)
                            add_sub.content = fix_line_ending(zf.read(name))
                            add_sub.full_data = name
                            additional_subs.append(add_sub)
                else:
                    sub.content = fix_line_ending(zf.read(zf.namelist()[0]))
                    sub.full_data = zf.namelist()[0]

        return subtitles + additional_subs
Esempio n. 4
0
    def _get_season_subtitles(self, show_id, season, sub_source):
        params = {
            "apikey": self.apikey,
            "show_id": show_id,
            "q": "Stagione %%%d" % season,
            "version": sub_source
        }
        r = self.session.get(self.server_url + "subtitles/search",
                             params=params,
                             timeout=30)
        r.raise_for_status()
        root = ElementTree.fromstring(r.content)

        if int(root.find("data/count").text) == 0:
            logger.warning(
                "Subtitles for season not found, try with rip suffix")

            params["version"] = sub_source + "rip"
            r = self.session.get(self.server_url + "subtitles/search",
                                 params=params,
                                 timeout=30)
            r.raise_for_status()
            root = ElementTree.fromstring(r.content)
            if int(root.find("data/count").text) == 0:
                logger.warning("Subtitles for season not found")
                return []

        subs = []
        # Looking for subtitles in first page
        season_re = re.compile(".*?stagione 0*?%d.*" % season)
        for subtitle in root.findall("data/subtitles/subtitle"):
            if season_re.match(subtitle.find("name").text.lower()):
                logger.debug("Found season zip id %d - %r - %r",
                             int(subtitle.find("id").text),
                             subtitle.find("name").text,
                             subtitle.find("version").text)

                content = self._download_zip(int(subtitle.find("id").text))
                if not is_zipfile(io.BytesIO(content)):  # pragma: no cover
                    if "limite di download" in content:
                        raise DownloadLimitExceeded()
                    else:
                        raise ConfigurationError("Not a zip file: %r" %
                                                 content)

                with ZipFile(io.BytesIO(content)) as zf:
                    episode_re = re.compile(r"s(\d{1,2})e(\d{1,2})")
                    for index, name in enumerate(zf.namelist()):
                        match = episode_re.search(name)
                        if not match:  # pragma: no cover
                            logger.debug("Cannot decode subtitle %r", name)
                        else:
                            sub = ItaSASubtitle(
                                int(subtitle.find("id").text),
                                subtitle.find("show_name").text,
                                int(match.group(1)), int(match.group(2)), None,
                                None, None, name)
                            sub.content = fix_line_ending(zf.read(name))
                            subs.append(sub)

        return subs
Esempio n. 5
0
def checked(fn,
            raise_api_limit=False,
            validate_token=False,
            validate_json=False,
            json_key_name=None,
            validate_content=False):
    """Run :fn: and check the response status before returning it.

    :param fn: the function to make an API call to OpenSubtitles.com.
    :param raise_api_limit: if True we wait a little bit longer before running the call again.
    :param validate_token: test if token is valid and return 401 if not.
    :param validate_json: test if response is valid json.
    :param json_key_name: test if returned json contain a specific key.
    :param validate_content: test if response have a content (used with download).
    :return: the response.

    """
    response = None
    try:
        try:
            response = fn()
        except APIThrottled:
            if not raise_api_limit:
                logger.info(
                    "API request limit hit, waiting and trying again once.")
                time.sleep(2)
                return checked(fn, raise_api_limit=True)
            raise
        except (ConnectionError, Timeout, ReadTimeout):
            raise ServiceUnavailable(
                f'Unknown Error, empty response: {response.status_code}: {response}'
            )
        except Exception:
            logging.exception('Unhandled exception raised.')
            raise ProviderError('Unhandled exception raised. Check log.')
        else:
            status_code = response.status_code
    except Exception:
        status_code = None
    else:
        if status_code == 401:
            if validate_token:
                return 401
            else:
                raise AuthenticationError(f'Login failed: {response.reason}')
        elif status_code == 403:
            raise ProviderError("Bazarr API key seems to be in problem")
        elif status_code == 406:
            raise DownloadLimitExceeded("Daily download limit reached")
        elif status_code == 410:
            raise ProviderError("Download as expired")
        elif status_code == 429:
            raise TooManyRequests()
        elif status_code == 502:
            # this one should deal with Bad Gateway issue on their side.
            raise APIThrottled()
        elif 500 <= status_code <= 599:
            raise ProviderError(response.reason)

        if status_code != 200:
            raise ProviderError(f'Bad status code: {response.status_code}')

        if validate_json:
            try:
                json_test = response.json()
            except JSONDecodeError:
                raise ProviderError('Invalid JSON returned by provider')
            else:
                if json_key_name not in json_test:
                    raise ProviderError(
                        f'Invalid JSON returned by provider: no {json_key_name} key in returned json.'
                    )

        if validate_content:
            if not hasattr(response, 'content'):
                logging.error('Download link returned no content attribute.')
                return False
            elif not response.content:
                logging.error(
                    f'This download link returned empty content: {response.url}'
                )
                return False

    return response