Пример #1
0
    def write_ep_file(self, ep_obj):
        """
        Generates and writes ep_obj's metadata under the given path with the
        given filename root. Uses the episode's name with the extension in
        _ep_nfo_extension.

        ep_obj: Episode object for which to create the metadata

        file_name_path: The file name to use for this metadata. Note that the extension
                will be automatically added based on _ep_nfo_extension. This should
                include an absolute path.

        Note that this method expects that _ep_data will return an ElementTree
        object. If your _ep_data returns data in another format you'll need to
        override this method.
        """

        data = self._ep_data(ep_obj)

        if not data:
            return False

        nfo_file_path = self.get_episode_file_path(ep_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        if not (nfo_file_path and nfo_file_dir):
            log.debug(
                u'Unable to write episode nfo file because episode location is missing.'
            )
            return False

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    'Metadata directory did not exist, creating it at {location}',
                    {'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug('Writing episode nfo file to {location}',
                      {'location': nfo_file_path})

            with io.open(nfo_file_path, 'wb') as nfo_file:
                # Calling encode directly, b/c often descriptions have wonky characters.
                data.write(nfo_file, encoding='utf-8', xml_declaration=True)

            helpers.chmod_as_parent(nfo_file_path)

        except IOError as e:
            log.error(
                'Unable to write file to {location} - are you sure the folder is writable? {error}',
                {
                    'location': nfo_file_path,
                    'error': ex(e)
                })
            return False

        return True
Пример #2
0
    def write_ep_file(self, ep_obj):
        """
        Generates and writes ep_obj's metadata under the given path with the
        given filename root. Uses the episode's name with the extension in
        _ep_nfo_extension.

        ep_obj: Episode object for which to create the metadata

        file_name_path: The file name to use for this metadata. Note that the extension
                will be automatically added based on _ep_nfo_extension. This should
                include an absolute path.
        """

        data = self._ep_data(ep_obj)

        if not data:
            return False

        nfo_file_path = self.get_episode_file_path(ep_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        if not (nfo_file_path and nfo_file_dir):
            log.debug(
                u'Unable to write episode nfo file because episode location is missing.'
            )
            return False

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    u'Metadata directory missing, creating it at {location}',
                    {'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug(u'Writing episode nfo file to {location}',
                      {'location': nfo_file_path})

            with io.open(nfo_file_path, 'wb') as nfo_file:
                # Calling encode directly, b/c often descriptions have wonky characters.
                nfo_file.write(data.encode('utf-8'))

            helpers.chmod_as_parent(nfo_file_path)

        except EnvironmentError as e:
            log.error(
                u'Unable to write file to {path} - are you sure the folder is writable? {error}',
                {
                    'path': nfo_file_path,
                    'error': ex(e)
                })
            return False

        return True
Пример #3
0
    def update_show_indexer_metadata(self, show_obj):
        if self.show_metadata and show_obj and self._has_show_metadata(
                show_obj):
            log.debug(
                u'Metadata provider {name} updating series indexer info metadata file for {series}',
                {
                    u'name': self.name,
                    u'series': show_obj.name
                })

            nfo_file_path = self.get_show_file_path(show_obj)

            try:
                with io.open(nfo_file_path, u'rb') as xmlFileObj:
                    showXML = etree.ElementTree(file=xmlFileObj)

                indexerid = showXML.find(u'id')

                root = showXML.getroot()
                if indexerid is not None:
                    indexerid.text = str(show_obj.indexerid)
                else:
                    etree.SubElement(root,
                                     u'id').text = str(show_obj.indexerid)

                # Make it purdy
                helpers.indent_xml(root)

                showXML.write(nfo_file_path, encoding=u'UTF-8')
                helpers.chmod_as_parent(nfo_file_path)

                return True
            except etree.ParseError as error:
                log.warning(
                    u'Received an invalid XML for {series}, try again later. Error: {error}',
                    {
                        u'series': show_obj.name,
                        u'error': error
                    })
            except IOError as error:
                if error.errno == errno.EACCES:
                    log.warning(
                        u'Unable to write metadata file to {location} - verify that the path is writeable',
                        {u'location': nfo_file_path})
                else:
                    log.error(
                        u'Unable to write metadata file to {location}. Error: {error!r}',
                        {
                            u'location': nfo_file_path,
                            u'error': error
                        })
Пример #4
0
    def write_ep_file(self, ep_obj):
        """
        Generates and writes ep_obj's metadata under the given path with the
        given filename root. Uses the episode's name with the extension in
        _ep_nfo_extension.

        ep_obj: Episode object for which to create the metadata

        file_name_path: The file name to use for this metadata. Note that the extension
                will be automatically added based on _ep_nfo_extension. This should
                include an absolute path.

        Note that this method expects that _ep_data will return an ElementTree
        object. If your _ep_data returns data in another format you'll need to
        override this method.
        """

        data = self._ep_data(ep_obj)

        if not data:
            return False

        nfo_file_path = self.get_episode_file_path(ep_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        if not (nfo_file_path and nfo_file_dir):
            log.debug(u'Unable to write episode nfo file because episode location is missing.')
            return False

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug('Metadata directory did not exist, creating it at {location}',
                          {'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug('Writing episode nfo file to {location}',
                      {'location': nfo_file_path})

            with io.open(nfo_file_path, 'wb') as nfo_file:
                # Calling encode directly, b/c often descriptions have wonky characters.
                data.write(nfo_file, encoding='utf-8', xml_declaration=True)

            helpers.chmod_as_parent(nfo_file_path)

        except IOError as e:
            log.error('Unable to write file to {location} - are you sure the folder is writable? {error}',
                      {'location': nfo_file_path, 'error': ex(e)})
            return False

        return True
Пример #5
0
    def write_ep_file(self, ep_obj):
        """
        Generates and writes ep_obj's metadata under the given path with the
        given filename root. Uses the episode's name with the extension in
        _ep_nfo_extension.

        ep_obj: Episode object for which to create the metadata

        file_name_path: The file name to use for this metadata. Note that the extension
                will be automatically added based on _ep_nfo_extension. This should
                include an absolute path.

        Note that this method expects that _ep_data will return an ElementTree
        object. If your _ep_data returns data in another format you'll need to
        override this method.
        """
        data = self._ep_data(ep_obj)

        if not data:
            return False

        nfo_file_path = self.get_episode_file_path(ep_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        if not (nfo_file_path and nfo_file_dir):
            log.debug(
                u'Unable to write episode nfo file because episode location is missing.'
            )
            return False

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    u'Metadata directory missing, creating it at {location}',
                    {u'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug(u'Writing episode nfo file to {location}',
                      {u'location': nfo_file_path})
            nfo_file = io.open(nfo_file_path, u'wb')
            data.write(nfo_file, encoding=u'UTF-8')
            nfo_file.close()
            helpers.chmod_as_parent(nfo_file_path)
        except IOError as e:
            exception_handler.handle(e,
                                     u'Unable to write file to {location}',
                                     location=nfo_file_path)
            return False

        return True
Пример #6
0
    def write_show_file(self, show_obj):
        """
        Generates and writes show_obj's metadata under the given path to the
        filename given by get_show_file_path()

        show_obj: Series object for which to create the metadata

        path: An absolute or relative path where we should put the file. Note that
                the file name will be the default show_file_name.

        Note that this method expects that _show_data will return an ElementTree
        object. If your _show_data returns data in another format you'll need to
        override this method.
        """

        data = self._show_data(show_obj)

        if not data:
            return False

        nfo_file_path = self.get_show_file_path(show_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    'Metadata directory did not exist, creating it at {location}',
                    {'location': nfo_file_dir}
                )
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug(
                'Writing show nfo file to {location}',
                {'location': nfo_file_dir}
            )

            nfo_file = io.open(nfo_file_path, 'wb')

            data.write(nfo_file, encoding='utf-8', xml_declaration=True)
            nfo_file.close()
            helpers.chmod_as_parent(nfo_file_path)
        except IOError as error:
            log.error(
                'Unable to write file to {location} - are you sure the folder is writable? {error}',
                {'location': nfo_file_path, 'error': ex(error)}
            )
            return False

        return True
Пример #7
0
    def write_ep_file(self, ep_obj):
        """
        Add episode information to the .plexmatch file.

        The episode hint:value pairs are used to match an episode filename to a specific episode.

        Uses the format of:
        ep: S01E12: /Season 01/Episode 12 - Finale Part 2.mkv

        :param ep_obj: Episode object for which to create the metadata
        """
        # Parse existing .flexmatch data
        flexmatch_file_path = self.get_show_file_path(ep_obj.series)
        flexmatch_file_dir = os.path.dirname(flexmatch_file_path)

        with open(flexmatch_file_path) as f:
            current_content = f.readlines()

        data = self._ep_data(current_content, ep_obj)

        if not data:
            return False

        if not (flexmatch_file_path and flexmatch_file_dir):
            log.debug(
                'Unable to write episode flexmatch file because episode location is missing.'
            )
            return False

        try:
            if not os.path.isdir(flexmatch_file_dir):
                log.debug(
                    'Metadata directory missing, creating it at {location}',
                    {'location': flexmatch_file_dir})
                os.makedirs(flexmatch_file_dir)
                helpers.chmod_as_parent(flexmatch_file_dir)

            log.debug('Writing episode flexmatch file to {location}',
                      {'location': flexmatch_file_path})

            with open(flexmatch_file_path, 'w') as outfile:
                outfile.write('\n'.join(data))

            helpers.chmod_as_parent(flexmatch_file_path)
        except IOError:
            log.error('Unable to write file to {location}',
                      {'location': flexmatch_file_path})
            return False

        return True
Пример #8
0
    def write_show_file(self, show_obj):
        """
        Generates and writes show_obj's metadata under the given path to the
        filename given by get_show_file_path()

        show_obj: Series object for which to create the metadata

        path: An absolute or relative path where we should put the file. Note that
                the file name will be the default show_file_name.

        Note that this method expects that _show_data will return an ElementTree
        object. If your _show_data returns data in another format you'll need to
        override this method.
        """

        data = self._show_data(show_obj)

        if not data:
            return False

        nfo_file_path = self.get_show_file_path(show_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    'Metadata directory did not exist, creating it at {location}',
                    {'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug('Writing show nfo file to {location}',
                      {'location': nfo_file_dir})

            nfo_file = io.open(nfo_file_path, 'wb')

            data.write(nfo_file, encoding='utf-8', xml_declaration=True)
            nfo_file.close()
            helpers.chmod_as_parent(nfo_file_path)
        except IOError as error:
            log.error(
                'Unable to write file to {location} - are you sure the folder is writable? {error}',
                {
                    'location': nfo_file_path,
                    'error': ex(error)
                })
            return False

        return True
Пример #9
0
    def dump_html(data):
        """Dump html data."""
        dump_name = os.path.join(app.CACHE_DIR, 'custom_torrent.html')

        try:
            file_out = io.open(dump_name, 'wb')
            file_out.write(data)
            file_out.close()
            helpers.chmod_as_parent(dump_name)
        except IOError as error:
            log.error('Unable to save the file: {0}', error)
            return False

        log.info('Saved custom_torrent html dump {0} ', dump_name)
        return True
Пример #10
0
    def dump_html(data):
        """Dump html data."""
        dump_name = os.path.join(app.CACHE_DIR, 'custom_torrent.html')

        try:
            file_out = io.open(dump_name, 'wb')
            file_out.write(data)
            file_out.close()
            helpers.chmod_as_parent(dump_name)
        except IOError as error:
            log.error('Unable to save the file: {0}', error)
            return False

        log.info('Saved custom_torrent html dump {0} ', dump_name)
        return True
Пример #11
0
def save_subs(tv_episode, video, found_subtitles, video_path=None):
    """Save subtitles.

    :param tv_episode: the episode to download subtitles
    :type tv_episode: sickbeard.tv.Episode
    :param video:
    :type video: subliminal.Video
    :param found_subtitles:
    :type found_subtitles: list of subliminal.Subtitle
    :param video_path: the video path. If none, the episode location will be used
    :type video_path: str
    :return: a sorted list of the opensubtitles codes for the downloaded subtitles
    :rtype: list of str
    """
    video_path = video_path or tv_episode.location
    show_name = tv_episode.series.name
    season = tv_episode.season
    episode = tv_episode.episode
    episode_name = tv_episode.name
    show_indexerid = tv_episode.series.indexerid
    subtitles_dir = get_subtitles_dir(video_path)
    saved_subtitles = save_subtitles(video, found_subtitles, directory=subtitles_dir,
                                     single=not app.SUBTITLES_MULTI, encoding='utf-8')

    for subtitle in saved_subtitles:
        logger.info(u'Found subtitle for %s in %s provider with language %s', os.path.basename(video_path),
                    subtitle.provider_name, subtitle.language.opensubtitles)
        subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
        helpers.chmod_as_parent(subtitle_path)
        helpers.fix_set_group_id(subtitle_path)

        if app.SUBTITLES_EXTRA_SCRIPTS and is_media_file(video_path):
            subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
            run_subs_extra_scripts(video_path=video_path, subtitle_path=subtitle_path,
                                   subtitle_language=subtitle.language, show_name=show_name, season=season,
                                   episode=episode, episode_name=episode_name, show_indexerid=show_indexerid)

        if app.SUBTITLES_HISTORY:
            logger.debug(u'Logging to history downloaded subtitle from provider %s and language %s',
                         subtitle.provider_name, subtitle.language.opensubtitles)
            history.log_subtitle(tv_episode, subtitle)

    # Refresh the subtitles property
    if tv_episode.location:
        tv_episode.refresh_subtitles()

    return sorted({subtitle.language.opensubtitles for subtitle in saved_subtitles})
Пример #12
0
def save_subs(tv_episode, video, found_subtitles, video_path=None):
    """Save subtitles.

    :param tv_episode: the episode to download subtitles
    :type tv_episode: sickbeard.tv.Episode
    :param video:
    :type video: subliminal.Video
    :param found_subtitles:
    :type found_subtitles: list of subliminal.Subtitle
    :param video_path: the video path. If none, the episode location will be used
    :type video_path: str
    :return: a sorted list of the opensubtitles codes for the downloaded subtitles
    :rtype: list of str
    """
    video_path = video_path or tv_episode.location
    show_name = tv_episode.series.name
    season = tv_episode.season
    episode = tv_episode.episode
    episode_name = tv_episode.name
    show_indexerid = tv_episode.series.indexerid
    subtitles_dir = get_subtitles_dir(video_path)
    saved_subtitles = save_subtitles(video, found_subtitles, directory=subtitles_dir,
                                     single=not app.SUBTITLES_MULTI, encoding='utf-8')

    for subtitle in saved_subtitles:
        logger.info(u'Found subtitle for %s in %s provider with language %s', os.path.basename(video_path),
                    subtitle.provider_name, subtitle.language.opensubtitles)
        subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
        helpers.chmod_as_parent(subtitle_path)
        helpers.fix_set_group_id(subtitle_path)

        if app.SUBTITLES_EXTRA_SCRIPTS and is_media_file(video_path):
            subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
            run_subs_extra_scripts(video_path=video_path, subtitle_path=subtitle_path,
                                   subtitle_language=subtitle.language, show_name=show_name, season=season,
                                   episode=episode, episode_name=episode_name, show_indexerid=show_indexerid)

        if app.SUBTITLES_HISTORY:
            logger.debug(u'Logging to history downloaded subtitle from provider %s and language %s',
                         subtitle.provider_name, subtitle.language.opensubtitles)
            history.log_subtitle(tv_episode, subtitle)

    # Refresh the subtitles property
    if tv_episode.location:
        tv_episode.refresh_subtitles()

    return sorted({subtitle.language.opensubtitles for subtitle in saved_subtitles})
Пример #13
0
def _download_result(result):
    """
    Download a result to the appropriate black hole folder.

    :param result: SearchResult instance to download.
    :return: boolean, True on success
    """
    res_provider = result.provider
    if res_provider is None:
        log.error(
            u'Invalid provider name - this is a coding error, report it please'
        )
        return False

    # nzbs with an URL can just be downloaded from the provider
    if result.result_type == u'nzb':
        new_result = res_provider.download_result(result)
    # if it's an nzb data result
    elif result.result_type == u'nzbdata':

        # get the final file path to the nzb
        file_name = os.path.join(app.NZB_DIR, result.name + u'.nzb')

        log.info(u'Saving NZB to {0}', file_name)

        new_result = True

        # save the data to disk
        try:
            with open(file_name, u'w') as file_out:
                file_out.write(result.extra_info[0])

            chmod_as_parent(file_name)

        except EnvironmentError as e:
            log.error(u'Error trying to save NZB to black hole: {0}', ex(e))
            new_result = False
    elif result.result_type == u'torrent':
        new_result = res_provider.download_result(result)
    else:
        log.error(
            u'Invalid provider type - this is a coding error, report it please'
        )
        new_result = False

    return new_result
Пример #14
0
    def write_show_file(self, show_obj):
        """
        Generates and writes show_obj's metadata under the given path to the
        filename given by get_show_file_path()

        show_obj: Series object for which to create the metadata

        path: An absolute or relative path where we should put the file. Note that
                the file name will be the default show_file_name.

        Note that this method expects that _show_data will return an ElementTree
        object. If your _show_data returns data in another format you'll need to
        override this method.
        """

        data = self._show_data(show_obj)

        if not data:
            return False

        nfo_file_path = self.get_show_file_path(show_obj)
        nfo_file_dir = os.path.dirname(nfo_file_path)

        try:
            if not os.path.isdir(nfo_file_dir):
                log.debug(
                    u'Metadata directory missing, creating it at {location}',
                    {u'location': nfo_file_dir})
                os.makedirs(nfo_file_dir)
                helpers.chmod_as_parent(nfo_file_dir)

            log.debug(u'Writing show nfo file to {location}',
                      {u'location': nfo_file_path})

            nfo_file = io.open(nfo_file_path, u'wb')
            data.write(nfo_file, encoding=u'UTF-8')
            nfo_file.close()
            helpers.chmod_as_parent(nfo_file_path)
        except IOError as e:
            exception_handler.handle(e,
                                     u'Unable to write file to {location}',
                                     location=nfo_file_path)
            return False

        return True
Пример #15
0
    def write_show_file(self, show_obj):
        """
        Generate and write show_obj's metadata under the given path to the filename given by get_show_file_path().

        show_obj: Series object for which to create the metadata

        Note that this method expects that _show_data will return a string,
        which will be written to a text file.
        """
        data = self._show_data(show_obj)

        if not data:
            return False

        flexmatch_file_path = self.get_show_file_path(show_obj)
        flexmatch_file_dir = os.path.dirname(flexmatch_file_path)

        try:
            if not os.path.isdir(flexmatch_file_dir):
                log.debug(
                    'Metadata directory did not exist, creating it at {location}',
                    {'location': flexmatch_file_dir})
                os.makedirs(flexmatch_file_dir)
                helpers.chmod_as_parent(flexmatch_file_dir)

            log.debug('Writing show flexmatch file to {location}',
                      {'location': flexmatch_file_dir})

            flexmatch_file = io.open(flexmatch_file_path, 'wb')
            flexmatch_file.write(data.encode('utf-8'))
            flexmatch_file.close()
            helpers.chmod_as_parent(flexmatch_file_path)
        except IOError as error:
            log.error(
                'Unable to write file to {location} - are you sure the folder is writable? {error}',
                {
                    'location': flexmatch_file_path,
                    'error': error
                })
            return False

        return True
Пример #16
0
def _download_result(result):
    """
    Download a result to the appropriate black hole folder.

    :param result: SearchResult instance to download.
    :return: boolean, True on success
    """
    res_provider = result.provider
    if res_provider is None:
        log.error(u'Invalid provider name - this is a coding error, report it please')
        return False

    # nzbs with an URL can just be downloaded from the provider
    if result.result_type == u'nzb':
        new_result = res_provider.download_result(result)
    # if it's an nzb data result
    elif result.result_type == u'nzbdata':

        # get the final file path to the nzb
        file_name = os.path.join(app.NZB_DIR, result.name + u'.nzb')

        log.info(u'Saving NZB to {0}', file_name)

        new_result = True

        # save the data to disk
        try:
            with open(file_name, u'w') as file_out:
                file_out.write(result.extra_info[0])

            chmod_as_parent(file_name)

        except EnvironmentError as e:
            log.error(u'Error trying to save NZB to black hole: {0}', ex(e))
            new_result = False
    elif result.result_type == u'torrent':
        new_result = res_provider.download_result(result)
    else:
        log.error(u'Invalid provider type - this is a coding error, report it please')
        new_result = False

    return new_result
Пример #17
0
    def _write_image(self, image_data, image_path, obj=None):
        """
        Saves the data in image_data to the location image_path. Returns True/False
        to represent success or failure.

        image_data: binary image data to write to file
        image_path: file location to save the image to
        """

        # don't bother overwriting it
        if os.path.isfile(image_path):
            log.debug(u'Image already exists, not downloading')
            return False

        image_dir = os.path.dirname(image_path)

        if not image_data:
            log.debug(
                u'Unable to retrieve image to save in {location}, skipping',
                {u'location': image_path})
            return False

        try:
            if not os.path.isdir(image_dir):
                log.debug(
                    u'Metadata directory missing, creating it at {location}',
                    {u'location': image_path})
                os.makedirs(image_dir)
                helpers.chmod_as_parent(image_dir)

            outFile = io.open(image_path, u'wb')
            outFile.write(image_data)
            outFile.close()
            helpers.chmod_as_parent(image_path)
        except IOError as e:
            exception_handler.handle(e,
                                     u'Unable to write image to {location}',
                                     location=image_path)
            return False

        return True
Пример #18
0
def get_subtitles_dir(video_path):
    """Return the correct subtitles directory based on the user configuration.

    If the directory doesn't exist, it will be created

    :param video_path: the video path
    :type video_path: str
    :return: the subtitles directory
    :rtype: str
    """
    if not app.SUBTITLES_DIR:
        return os.path.dirname(video_path)

    if os.path.isabs(app.SUBTITLES_DIR):
        return _decode(app.SUBTITLES_DIR)

    new_subtitles_path = os.path.join(os.path.dirname(video_path), app.SUBTITLES_DIR)
    if helpers.make_dir(new_subtitles_path):
        helpers.chmod_as_parent(new_subtitles_path)
    else:
        logger.warning(u'Unable to create subtitles folder %s', new_subtitles_path)

    return new_subtitles_path
Пример #19
0
def get_subtitles_dir(video_path):
    """Return the correct subtitles directory based on the user configuration.

    If the directory doesn't exist, it will be created

    :param video_path: the video path
    :type video_path: str
    :return: the subtitles directory
    :rtype: str
    """
    if not app.SUBTITLES_DIR:
        return os.path.dirname(video_path)

    if os.path.isabs(app.SUBTITLES_DIR):
        return _decode(app.SUBTITLES_DIR)

    new_subtitles_path = os.path.join(os.path.dirname(video_path), app.SUBTITLES_DIR)
    if helpers.make_dir(new_subtitles_path):
        helpers.chmod_as_parent(new_subtitles_path)
    else:
        logger.warning(u'Unable to create subtitles folder %s', new_subtitles_path)

    return new_subtitles_path
Пример #20
0
    def addNewShow(self,
                   whichSeries=None,
                   indexer_lang=None,
                   rootDir=None,
                   defaultStatus=None,
                   quality_preset=None,
                   allowed_qualities=None,
                   preferred_qualities=None,
                   season_folders=None,
                   subtitles=None,
                   fullShowPath=None,
                   other_shows=None,
                   skipShow=None,
                   providedIndexer=None,
                   anime=None,
                   scene=None,
                   blacklist=None,
                   whitelist=None,
                   defaultStatusAfter=None):
        """
        Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
        provided then it forwards back to newShow, if not it goes to /home.
        """
        provided_indexer = providedIndexer

        indexer_lang = app.INDEXER_DEFAULT_LANGUAGE if not indexer_lang else indexer_lang

        # grab our list of other dirs if given
        if not other_shows:
            other_shows = []
        elif not isinstance(other_shows, list):
            other_shows = [other_shows]

        def finishAddShow():
            # if there are no extra shows then go home
            if not other_shows:
                return json_redirect('/home/')

            # go to add the next show
            return json_redirect(
                '/addShows/newShow/',
                [('show_to_add' if not i else 'other_shows', cur_dir)
                 for i, cur_dir in enumerate(other_shows)])

        # if we're skipping then behave accordingly
        if skipShow:
            return finishAddShow()

        # sanity check on our inputs
        if (not rootDir and not fullShowPath) or not whichSeries:
            return 'Missing params, no Indexer ID or folder:{series!r} and {root!r}/{path!r}'.format(
                series=whichSeries, root=rootDir, path=fullShowPath)

        # figure out what show we're adding and where
        series_pieces = whichSeries.split('|')
        if (whichSeries and rootDir) or (whichSeries and fullShowPath
                                         and len(series_pieces) > 1):
            if len(series_pieces) < 6:
                logger.log(
                    u'Unable to add show due to show selection. Not enough arguments: %s'
                    % (repr(series_pieces)), logger.ERROR)
                ui.notifications.error(
                    'Unknown error. Unable to add show due to problem with show selection.'
                )
                return json_redirect('/addShows/existingShows/')

            indexer = int(series_pieces[1])
            indexer_id = int(series_pieces[3])
            show_name = series_pieces[4]
        else:
            # if no indexer was provided use the default indexer set in General settings
            if not provided_indexer:
                provided_indexer = app.INDEXER_DEFAULT

            indexer = int(provided_indexer)
            indexer_id = int(whichSeries)
            show_name = os.path.basename(os.path.normpath(fullShowPath))

        # use the whole path if it's given, or else append the show name to the root dir to get the full show path
        if fullShowPath:
            show_dir = os.path.normpath(fullShowPath)
        else:
            show_dir = os.path.join(rootDir, sanitize_filename(show_name))

        # blanket policy - if the dir exists you should have used 'add existing show' numbnuts
        if os.path.isdir(show_dir) and not fullShowPath:
            ui.notifications.error(
                'Unable to add show',
                'Folder {path} exists already'.format(path=show_dir))
            return json_redirect('/addShows/existingShows/')

        # don't create show dir if config says not to
        if app.ADD_SHOWS_WO_DIR:
            logger.log(
                u'Skipping initial creation of {path} due to config.ini setting'
                .format(path=show_dir))
        else:
            dir_exists = helpers.make_dir(show_dir)
            if not dir_exists:
                logger.log(
                    u'Unable to create the folder {path}, can\'t add the show'.
                    format(path=show_dir), logger.ERROR)
                ui.notifications.error(
                    'Unable to add show',
                    'Unable to create the folder {path}, can\'t add the show'.
                    format(path=show_dir))
                # Don't redirect to default page because user wants to see the new show
                return json_redirect('/home/')
            else:
                helpers.chmod_as_parent(show_dir)

        # prepare the inputs for passing along
        scene = config.checkbox_to_value(scene)
        anime = config.checkbox_to_value(anime)
        season_folders = config.checkbox_to_value(season_folders)
        subtitles = config.checkbox_to_value(subtitles)

        if whitelist:
            whitelist = short_group_names(whitelist)
        if blacklist:
            blacklist = short_group_names(blacklist)

        if not allowed_qualities:
            allowed_qualities = []
        if not preferred_qualities or try_int(quality_preset, None):
            preferred_qualities = []
        if not isinstance(allowed_qualities, list):
            allowed_qualities = [allowed_qualities]
        if not isinstance(preferred_qualities, list):
            preferred_qualities = [preferred_qualities]
        new_quality = Quality.combine_qualities(
            [int(q) for q in allowed_qualities],
            [int(q) for q in preferred_qualities])

        # add the show
        app.show_queue_scheduler.action.addShow(indexer, indexer_id, show_dir,
                                                int(defaultStatus),
                                                new_quality, season_folders,
                                                indexer_lang, subtitles, anime,
                                                scene, None, blacklist,
                                                whitelist,
                                                int(defaultStatusAfter))
        ui.notifications.message(
            'Show added',
            'Adding the specified show into {path}'.format(path=show_dir))

        return finishAddShow()
Пример #21
0
    def addNewShow(self, whichSeries=None, indexer_lang=None, rootDir=None, defaultStatus=None, quality_preset=None,
                   allowed_qualities=None, preferred_qualities=None, season_folders=None, subtitles=None,
                   fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None,
                   scene=None, blacklist=None, whitelist=None, defaultStatusAfter=None):
        """
        Receive tvdb id, dir, and other options and create a show from them. If extra show dirs are
        provided then it forwards back to newShow, if not it goes to /home.
        """
        provided_indexer = providedIndexer

        indexer_lang = app.INDEXER_DEFAULT_LANGUAGE if not indexer_lang else indexer_lang

        # grab our list of other dirs if given
        if not other_shows:
            other_shows = []
        elif not isinstance(other_shows, list):
            other_shows = [other_shows]

        other_shows = decode_shows(other_shows)

        def finishAddShow():
            # if there are no extra shows then go home
            if not other_shows:
                return json_response(redirect='/home/')

            # go to add the next show
            return json_response(
                redirect='/addShows/newShow/',
                params=[
                    ('show_to_add' if not i else 'other_shows', cur_dir)
                    for i, cur_dir in enumerate(other_shows)
                ]
            )

        # if we're skipping then behave accordingly
        if skipShow:
            return finishAddShow()

        # sanity check on our inputs
        if (not rootDir and not fullShowPath) or not whichSeries:
            error_msg = 'Missing params, no Indexer ID or folder: {series!r} and {root!r}/{path!r}'.format(
                series=whichSeries, root=rootDir, path=fullShowPath)
            log.error(error_msg)
            return json_response(
                result=False,
                message=error_msg,
                redirect='/home/'
            )

        # figure out what show we're adding and where
        series_pieces = whichSeries.split('|')
        if (whichSeries and rootDir) or (whichSeries and fullShowPath and len(series_pieces) > 1):
            if len(series_pieces) < 6:
                log.error('Unable to add show due to show selection. Not enough arguments: {pieces!r}',
                          {'pieces': series_pieces})
                ui.notifications.error('Unknown error. Unable to add show due to problem with show selection.')
                return json_response(
                    result=False,
                    message='Unable to add show due to show selection. Not enough arguments: {0!r}'.format(series_pieces),
                    redirect='/addShows/existingShows/'
                )

            indexer = int(series_pieces[1])
            indexer_id = int(series_pieces[3])
            show_name = series_pieces[4]
        else:
            # if no indexer was provided use the default indexer set in General settings
            if not provided_indexer:
                provided_indexer = app.INDEXER_DEFAULT

            indexer = int(provided_indexer)
            indexer_id = int(whichSeries)
            show_name = os.path.basename(os.path.normpath(fullShowPath))

        # use the whole path if it's given, or else append the show name to the root dir to get the full show path
        if fullShowPath:
            show_dir = os.path.normpath(fullShowPath)
        else:
            show_dir = os.path.join(rootDir, sanitize_filename(show_name))

        # blanket policy - if the dir exists you should have used 'add existing show' numbnuts
        if os.path.isdir(show_dir) and not fullShowPath:
            ui.notifications.error('Unable to add show', 'Folder {path} exists already'.format(path=show_dir))
            return json_response(
                result=False,
                message='Unable to add show: Folder {path} exists already'.format(path=show_dir),
                redirect='/addShows/existingShows/'
            )

        # don't create show dir if config says not to
        if app.ADD_SHOWS_WO_DIR:
            log.info('Skipping initial creation of {path} due to config.ini setting',
                     {'path': show_dir})
        else:
            dir_exists = helpers.make_dir(show_dir)
            if not dir_exists:
                log.error("Unable to create the folder {path}, can't add the show",
                          {'path': show_dir})
                ui.notifications.error('Unable to add show',
                                       'Unable to create the folder {path}, can\'t add the show'.format(path=show_dir))
                # Don't redirect to default page because user wants to see the new show
                return json_response(
                    result=False,
                    message='Unable to add show: Unable to create the folder {path}'.format(path=show_dir),
                    redirect='/home/'
                )
            else:
                helpers.chmod_as_parent(show_dir)

        # prepare the inputs for passing along
        scene = config.checkbox_to_value(scene)
        anime = config.checkbox_to_value(anime)
        season_folders = config.checkbox_to_value(season_folders)
        subtitles = config.checkbox_to_value(subtitles)

        if whitelist:
            if not isinstance(whitelist, list):
                whitelist = [whitelist]
            whitelist = short_group_names(whitelist)
        if blacklist:
            if not isinstance(blacklist, list):
                blacklist = [blacklist]
            blacklist = short_group_names(blacklist)

        if not allowed_qualities:
            allowed_qualities = []
        if not preferred_qualities or try_int(quality_preset, None):
            preferred_qualities = []
        if not isinstance(allowed_qualities, list):
            allowed_qualities = [allowed_qualities]
        if not isinstance(preferred_qualities, list):
            preferred_qualities = [preferred_qualities]
        new_quality = Quality.combine_qualities([int(q) for q in allowed_qualities], [int(q) for q in preferred_qualities])

        # add the show
        app.show_queue_scheduler.action.addShow(indexer, indexer_id, show_dir, int(defaultStatus), new_quality,
                                                season_folders, indexer_lang, subtitles, anime,
                                                scene, None, blacklist, whitelist, int(defaultStatusAfter))
        ui.notifications.message('Show added', 'Adding the specified show into {path}'.format(path=show_dir))

        return finishAddShow()
Пример #22
0
    def run(self):

        ShowQueueItem.run(self)

        logger.log(u"Starting to add show {0}".format(
            "by ShowDir: {0}".format(self.showDir) if self.
            showDir else u"by Indexer Id: {0}".format(self.indexer_id)))

        # make sure the Indexer IDs are valid
        try:
            l_indexer_api_params = indexerApi(self.indexer).api_params.copy()
            if self.lang:
                l_indexer_api_params['language'] = self.lang

            logger.log(u"" + str(indexerApi(self.indexer).name) + ": " +
                       repr(l_indexer_api_params))

            indexer_api = indexerApi(
                self.indexer).indexer(**l_indexer_api_params)
            s = indexer_api[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir
            # to build build using the Indexers provided series name
            if not self.showDir and self.root_dir:
                show_name = get_showname_from_indexer(self.indexer,
                                                      self.indexer_id,
                                                      self.lang)
                if show_name:
                    self.showDir = os.path.join(self.root_dir,
                                                sanitize_filename(show_name))
                    dir_exists = make_dir(self.showDir)
                    if not dir_exists:
                        logger.log(
                            u"Unable to create the folder {0}, can't add the show"
                            .format(self.showDir))
                        return

                    chmod_as_parent(self.showDir)
                else:
                    logger.log(
                        u"Unable to get a show {0}, can't add the show".format(
                            self.showDir))
                    return

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that
            # has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                logger.log(
                    u"Show in {0} has no name on {1}, probably searched with the wrong language."
                    .format(self.showDir,
                            indexerApi(self.indexer).name), logger.ERROR)

                ui.notifications.error(
                    'Unable to add show',
                    'Show in {0} has no name on {1}, probably the wrong language. \
                                       Delete .nfo and manually add the correct language.'
                    .format(self.showDir,
                            indexerApi(self.indexer).name))
                self._finishEarly()
                return
            # if the show has no episodes/seasons
            if not s:
                logger.log(u"Show " + str(s['seriesname']) + u" is on " +
                           str(indexerApi(self.indexer).name) +
                           u" but contains no season/episode data.")
                ui.notifications.error(
                    "Unable to add show",
                    "Show {0} is on {1} but contains no season/episode data.".
                    format(s['seriesname'],
                           indexerApi(self.indexer).name))
                self._finishEarly()

                return

            # Check if we can already find this show in our current showList.
            try:
                check_existing_shows(s, self.indexer)
            except IndexerShowAllreadyInLibrary as e:
                logger.log(
                    u"Could not add the show %s, as it already is in your library."
                    u" Error: %s" % (s['seriesname'], e.message),
                    logger.WARNING)
                ui.notifications.error('Unable to add show',
                                       'reason: {0}'.format(e.message))
                self._finishEarly()

                # Clean up leftover if the newly created directory is empty.
                delete_empty_folders(self.showDir)
                return

        # TODO: Add more specific indexer exceptions, that should provide the user with some accurate feedback.
        except IndexerShowIncomplete as e:
            logger.log(
                u"%s Error while loading information from indexer %s. "
                u"Error: %s" %
                (self.indexer_id, indexerApi(self.indexer).name, e.message),
                logger.WARNING)
            ui.notifications.error(
                "Unable to add show",
                "Unable to look up the show in {0} on {1} using ID {2} "
                "Reason: {3}".format(self.showDir,
                                     indexerApi(self.indexer).name,
                                     self.indexer_id, e.message))
            self._finishEarly()
            return
        except IndexerShowNotFoundInLanguage as e:
            logger.log(
                u'{id}: Data retrieved from {indexer} was incomplete. The indexer does not provide '
                u'show information in the searched language {language}. Aborting: {error_msg}'
                .format(id=self.indexer_id,
                        indexer=indexerApi(self.indexer).name,
                        language=e.language,
                        error_msg=e.message), logger.WARNING)
            ui.notifications.error(
                'Error adding show!',
                'Unable to add show {indexer_id} on {indexer} with this language: {language}'
                .format(indexer_id=self.indexer_id,
                        indexer=indexerApi(self.indexer).name,
                        language=e.language))
            self._finishEarly()
            return
        except Exception as e:
            logger.log(
                u"%s Error while loading information from indexer %s. "
                u"Error: %r" %
                (self.indexer_id, indexerApi(self.indexer).name, e.message),
                logger.ERROR)
            ui.notifications.error(
                "Unable to add show",
                "Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. "
                "Delete .nfo and try adding manually again.".format(
                    self.showDir,
                    indexerApi(self.indexer).name, self.indexer_id))
            self._finishEarly()
            return

        try:
            newShow = Series(self.indexer, self.indexer_id, self.lang)
            newShow.load_from_indexer(indexer_api)

            self.show = newShow

            # set up initial values
            self.show.location = self.showDir
            self.show.subtitles = self.subtitles if self.subtitles is not None else app.SUBTITLES_DEFAULT
            self.show.quality = self.quality if self.quality else app.QUALITY_DEFAULT
            self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None \
                else app.FLATTEN_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else app.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else app.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            logger.log(
                u"Setting all previously aired episodes to the specified status: {status}"
                .format(status=statusStrings[self.default_status]))
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(
                    self.show.indexerid)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

            # # be smartish about this
            # if self.show.genre and "talk show" in self.show.genre.lower():
            #     self.show.air_by_date = 1
            # if self.show.genre and "documentary" in self.show.genre.lower():
            #     self.show.air_by_date = 0
            # if self.show.classification and "sports" in self.show.classification.lower():
            #     self.show.sports = 1

        except IndexerException as e:
            logger.log(
                u"Unable to add show due to an error with " +
                indexerApi(self.indexer).name + ": " + e.message, logger.ERROR)
            if self.show:
                ui.notifications.error("Unable to add " + str(self.show.name) +
                                       " due to an error with " +
                                       indexerApi(self.indexer).name + "")
            else:
                ui.notifications.error(
                    "Unable to add show due to an error with " +
                    indexerApi(self.indexer).name + "")
            self._finishEarly()
            return

        except MultipleShowObjectsException:
            logger.log(
                u"The show in " + self.showDir +
                " is already in your show list, skipping", logger.WARNING)
            ui.notifications.error(
                'Show skipped', "The show in " + self.showDir +
                " is already in your show list")
            self._finishEarly()
            return

        except Exception as e:
            logger.log(u"Error trying to add show: " + e.message, logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        logger.log(u"Retrieving show info from IMDb", logger.DEBUG)
        try:
            self.show.load_imdb_info()
        except ImdbAPIError as e:
            logger.log(u"Something wrong on IMDb api: " + e.message,
                       logger.INFO)
        except Exception as e:
            logger.log(u"Error loading IMDb info: " + e.message, logger.ERROR)

        try:
            self.show.save_to_db()
        except Exception as e:
            logger.log(u"Error saving the show to the database: " + e.message,
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        # add it to the show list
        app.showList.append(self.show)

        try:
            self.show.load_episodes_from_indexer(tvapi=indexer_api)
        except Exception as e:
            logger.log(
                u"Error with " + indexerApi(self.show.indexer).name +
                ", not creating episode list: " + e.message, logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # update internal name cache
        name_cache.build_name_cache(self.show)

        try:
            self.show.load_episodes_from_dir()
        except Exception as e:
            logger.log(u"Error searching dir for episodes: " + e.message,
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # if they set default ep status to WANTED then run the backlog to search for episodes
        # FIXME: This needs to be a backlog queue item!!!
        if self.show.default_ep_status == WANTED:
            logger.log(
                u"Launching backlog for this show since its episodes are WANTED"
            )
            app.backlog_search_scheduler.action.search_backlog([self.show])

        self.show.write_metadata()
        self.show.update_metadata()
        self.show.populate_cache()

        self.show.flush_episodes()

        if app.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            app.trakt_checker_scheduler.action.manage_new_show(self.show)

            # add show to trakt.tv library
            if app.TRAKT_SYNC:
                app.trakt_checker_scheduler.action.add_show_trakt_library(
                    self.show)

            if app.TRAKT_SYNC_WATCHLIST:
                logger.log(u"update watchlist")
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        scene_numbering.xem_refresh(self.show.indexerid,
                                    self.show.indexer,
                                    force=True)

        # check if show has XEM mapping so we can determine if searches
        # should go by scene numbering or indexer numbering.
        if not self.scene and scene_numbering.get_xem_numbering_for_show(
                self.show.indexerid, self.show.indexer):
            self.show.scene = 1

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        self.finish()
Пример #23
0
    def run(self):

        ShowQueueItem.run(self)

        log.info('Starting to add show by {0}',
                 ('show_dir: {0}'.format(self.show_dir) if self.show_dir else
                  'Indexer Id: {0}'.format(self.indexer_id)))

        # make sure the Indexer IDs are valid
        try:
            l_indexer_api_params = indexerApi(self.indexer).api_params.copy()
            if self.lang:
                l_indexer_api_params['language'] = self.lang

            log.info(
                '{indexer_name}: {indexer_params!r}', {
                    'indexer_name': indexerApi(self.indexer).name,
                    'indexer_params': l_indexer_api_params
                })

            indexer_api = indexerApi(
                self.indexer).indexer(**l_indexer_api_params)
            s = indexer_api[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir
            # to build build using the Indexers provided series name
            if not self.show_dir and self.root_dir:
                show_name = get_showname_from_indexer(self.indexer,
                                                      self.indexer_id,
                                                      self.lang)
                if show_name:
                    self.show_dir = os.path.join(self.root_dir,
                                                 sanitize_filename(show_name))
                    dir_exists = make_dir(self.show_dir)
                    if not dir_exists:
                        log.info(
                            "Unable to create the folder {0}, can't add the show",
                            self.show_dir)
                        return

                    chmod_as_parent(self.show_dir)
                else:
                    log.info("Unable to get a show {0}, can't add the show",
                             self.show_dir)
                    return

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that
            # has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                log.error(
                    'Show in {path} has no name on {indexer}, probably searched with the wrong language.',
                    {
                        'path': self.show_dir,
                        'indexer': indexerApi(self.indexer).name
                    })

                ui.notifications.error(
                    'Unable to add show',
                    'Show in {path} has no name on {indexer}, probably the wrong language.'
                    ' Delete .nfo and manually add the correct language.'.
                    format(path=self.show_dir,
                           indexer=indexerApi(self.indexer).name))
                self._finishEarly()
                return

            # Check if we can already find this show in our current showList.
            try:
                check_existing_shows(s, self.indexer)
            except IndexerShowAlreadyInLibrary as error:
                log.warning(
                    'Could not add the show {series}, as it already is in your library.'
                    ' Error: {error}', {
                        'series': s['seriesname'],
                        'error': error
                    })
                ui.notifications.error('Unable to add show',
                                       'reason: {0}'.format(error))
                self._finishEarly()

                # Clean up leftover if the newly created directory is empty.
                delete_empty_folders(self.show_dir)
                return

        # TODO: Add more specific indexer exceptions, that should provide the user with some accurate feedback.
        except IndexerShowNotFound as error:
            log.warning(
                '{id}: Unable to look up the show in {path} using id {id} on {indexer}.'
                ' Delete metadata files from the folder and try adding it again.\n'
                'With error: {error}', {
                    'id': self.indexer_id,
                    'path': self.show_dir,
                    'indexer': indexerApi(self.indexer).name,
                    'error': error
                })
            ui.notifications.error(
                'Unable to add show',
                'Unable to look up the show in {path} using id {id} on {indexer}.'
                ' Delete metadata files from the folder and try adding it again.'
                .format(path=self.show_dir,
                        id=self.indexer_id,
                        indexer=indexerApi(self.indexer).name))
            self._finishEarly()
            return
        except IndexerShowNotFoundInLanguage as error:
            log.warning(
                '{id}: Data retrieved from {indexer} was incomplete. The indexer does not provide'
                ' show information in the searched language {language}. Aborting: {error_msg}',
                {
                    'id': self.indexer_id,
                    'indexer': indexerApi(self.indexer).name,
                    'language': error.language,
                    'error_msg': error
                })
            ui.notifications.error(
                'Error adding show!',
                'Unable to add show {indexer_id} on {indexer} with this language: {language}'
                .format(indexer_id=self.indexer_id,
                        indexer=indexerApi(self.indexer).name,
                        language=error.language))
            self._finishEarly()
            return
        except Exception as error:
            log.error(
                '{id}: Error while loading information from indexer {indexer}. Error: {error!r}',
                {
                    'id': self.indexer_id,
                    'indexer': indexerApi(self.indexer).name,
                    'error': error
                })
            ui.notifications.error(
                'Unable to add show',
                'Unable to look up the show in {path} on {indexer} using ID {id}.'
                .format(path=self.show_dir,
                        indexer=indexerApi(self.indexer).name,
                        id=self.indexer_id))
            self._finishEarly()
            return

        try:
            newShow = Series(self.indexer, self.indexer_id, self.lang)
            newShow.load_from_indexer(indexer_api)

            self.show = newShow

            # set up initial values
            self.show.location = self.show_dir
            self.show.subtitles = self.subtitles if self.subtitles is not None else app.SUBTITLES_DEFAULT
            self.show.quality = self.quality if self.quality else app.QUALITY_DEFAULT
            self.show.season_folders = self.season_folders if self.season_folders is not None \
                else app.SEASON_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else app.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else app.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            log.info(
                'Setting all previously aired episodes to the specified status: {status}',
                {'status': statusStrings[self.default_status]})
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(self.show)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

        except IndexerException as error:
            log.error(
                'Unable to add show due to an error with {indexer}: {error}', {
                    'indexer': indexerApi(self.indexer).name,
                    'error': error
                })
            ui.notifications.error(
                'Unable to add {series_name} due to an error with {indexer_name}'
                .format(series_name=self.show.name if self.show else 'show',
                        indexer_name=indexerApi(self.indexer).name))
            self._finishEarly()
            return

        except MultipleShowObjectsException:
            log.warning(
                'The show in {show_dir} is already in your show list, skipping',
                {'show_dir': self.show_dir})
            ui.notifications.error(
                'Show skipped',
                'The show in {show_dir} is already in your show list'.format(
                    show_dir=self.show_dir))
            self._finishEarly()
            return

        except Exception as error:
            log.error('Error trying to add show: {0}', error)
            log.debug(traceback.format_exc())
            self._finishEarly()
            raise

        log.debug('Retrieving show info from IMDb')
        try:
            self.show.load_imdb_info()
        except ImdbAPIError as error:
            log.info('Something wrong on IMDb api: {0}', error)
        except RequestException as error:
            log.warning('Error loading IMDb info: {0}', error)

        try:
            log.debug('{id}: Saving new show to database',
                      {'id': self.show.series_id})
            self.show.save_to_db()
        except Exception as error:
            log.error('Error saving the show to the database: {0}', error)
            log.debug(traceback.format_exc())
            self._finishEarly()
            raise

        # add it to the show list
        app.showList.append(self.show)

        try:
            self.show.load_episodes_from_indexer(tvapi=indexer_api)
        except Exception as error:
            log.error(
                'Error with {indexer}, not creating episode list: {error}', {
                    'indexer': indexerApi(self.show.indexer).name,
                    'error': error
                })
            log.debug(traceback.format_exc())

        # update internal name cache
        name_cache.build_name_cache(self.show)

        try:
            self.show.load_episodes_from_dir()
        except Exception as error:
            log.error('Error searching dir for episodes: {0}', error)
            log.debug(traceback.format_exc())

        # if they set default ep status to WANTED then run the backlog to search for episodes
        if self.show.default_ep_status == WANTED:
            log.info(
                'Launching backlog for this show since its episodes are WANTED'
            )
            wanted_segments = self.show.get_wanted_segments()
            for season, segment in viewitems(wanted_segments):
                cur_backlog_queue_item = BacklogQueueItem(self.show, segment)
                app.forced_search_queue_scheduler.action.add_item(
                    cur_backlog_queue_item)

                log.info('Sending forced backlog for {show} season {season}'
                         ' because some episodes were set to wanted'.format(
                             show=self.show.name, season=season))

        self.show.write_metadata()
        self.show.update_metadata()
        self.show.populate_cache()

        self.show.flush_episodes()

        if app.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            app.trakt_checker_scheduler.action.manage_new_show(self.show)

            # add show to trakt.tv library
            if app.TRAKT_SYNC:
                app.trakt_checker_scheduler.action.add_show_trakt_library(
                    self.show)

            if app.TRAKT_SYNC_WATCHLIST:
                log.info('update watchlist')
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        scene_numbering.xem_refresh(self.show, force=True)

        # check if show has XEM mapping so we can determine if searches
        # should go by scene numbering or indexer numbering. Warn the user.
        if not self.scene and scene_numbering.get_xem_numbering_for_show(
                self.show):
            log.warning(
                '{id}: while adding the show {title} we noticed thexem.de has an episode mapping available'
                '\nyou might want to consider enabling the scene option for this show.',
                {
                    'id': self.show.series_id,
                    'title': self.show.name
                })
            ui.notifications.message(
                'consider enabling scene for this show',
                'for show {title} you might want to consider enabling the scene option'
                .format(title=self.show.name))

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        try:
            log.debug('{id}: Saving new show info to database',
                      {'id': self.show.series_id})
            self.show.save_to_db()
        except Exception as error:
            log.warning(
                '{id}: Error saving new show info to database: {error_msg}', {
                    'id': self.show.series_id,
                    'error_msg': error
                })
            log.error(traceback.format_exc())

        # Send ws update to client
        ws.Message('showAdded', self.show.to_json(detailed=False)).push()

        self.finish()
Пример #24
0
    def mass_edit_show(
        self, show_obj, location=None, allowed_qualities=None, preferred_qualities=None,
        season_folders=None, paused=None, air_by_date=None, sports=None, dvd_order=None, subtitles=None,
        anime=None, scene=None, default_ep_status=None
    ):
        """A variation of the original `editShow`, where `directCall` is always true."""
        allowed_qualities = allowed_qualities or []
        preferred_qualities = preferred_qualities or []

        errors = 0

        do_update_scene_numbering = not (scene == show_obj.scene and anime == show_obj.anime)

        if not isinstance(allowed_qualities, list):
            allowed_qualities = [allowed_qualities]

        if not isinstance(preferred_qualities, list):
            preferred_qualities = [preferred_qualities]

        with show_obj.lock:
            new_quality = Quality.combine_qualities([int(q) for q in allowed_qualities],
                                                    [int(q) for q in preferred_qualities])
            show_obj.quality = new_quality

            # reversed for now
            if bool(show_obj.season_folders) != bool(season_folders):
                show_obj.season_folders = season_folders
                try:
                    app.show_queue_scheduler.action.refreshShow(show_obj)
                except CantRefreshShowException as error:
                    errors += 1
                    log.warning("Unable to refresh show '{show}': {error}", {
                        'show': show_obj.name, 'error': error
                    })

            # Check if we should erase parsed cached results for that show
            do_erase_parsed_cache = False
            for item in [('scene', scene), ('anime', anime), ('sports', sports),
                         ('air_by_date', air_by_date), ('dvd_order', dvd_order)]:
                if getattr(show_obj, item[0]) != item[1]:
                    do_erase_parsed_cache = True
                    # Break if at least one setting was changed
                    break

            show_obj.paused = paused
            show_obj.scene = scene
            show_obj.anime = anime
            show_obj.sports = sports
            show_obj.subtitles = subtitles
            show_obj.air_by_date = air_by_date
            show_obj.default_ep_status = int(default_ep_status)
            show_obj.dvd_order = dvd_order

            # if we change location clear the db of episodes, change it, write to db, and rescan
            old_location = path.normpath(show_obj._location)
            new_location = path.normpath(location)
            if old_location != new_location:
                changed_location = True
                log.info('Changing show location to: {new}', {'new': new_location})
                if not path.isdir(new_location):
                    if app.CREATE_MISSING_SHOW_DIRS:
                        log.info("Show directory doesn't exist, creating it")
                        try:
                            mkdir(new_location)
                        except OSError as error:
                            errors += 1
                            changed_location = False
                            log.warning("Unable to create the show directory '{location}'. Error: {msg}", {
                                        'location': new_location, 'msg': error})
                        else:
                            log.info('New show directory created')
                            helpers.chmod_as_parent(new_location)
                    else:
                        changed_location = False
                        log.warning("New location '{location}' does not exist. "
                                    "Enable setting 'Create missing show dirs'", {'location': location})

                # Save new location to DB only if we changed it
                if changed_location:
                    show_obj.location = new_location

                if changed_location and path.isdir(new_location):
                    try:
                        app.show_queue_scheduler.action.refreshShow(show_obj)
                    except CantRefreshShowException as error:
                        errors += 1
                        log.warning("Unable to refresh show '{show}'. Error: {error}", {
                                    'show': show_obj.name, 'error': error})

            # Save all settings changed while in show_obj.lock
            show_obj.save_to_db()

        if do_update_scene_numbering or do_erase_parsed_cache:
            try:
                xem_refresh(show_obj)
            except CantUpdateShowException as error:
                errors += 1
                log.warning("Unable to update scene numbering for show '{show}': {error}",
                            {'show': show_obj.name, 'error': error})

            # Must erase cached DB results when toggling scene numbering
            show_obj.erase_provider_cache()

            # Erase parsed cached names as we are changing scene numbering
            show_obj.flush_episodes()
            show_obj.erase_cached_parse()

            # Need to refresh show as we updated scene numbering or changed show format
            try:
                app.show_queue_scheduler.action.refreshShow(show_obj)
            except CantRefreshShowException as error:
                errors += 1
                log.warning(
                    "Unable to refresh show '{show}'. Please manually trigger a full show refresh. "
                    'Error: {error!r}'.format(show=show_obj.name, error=error),
                    {'show': show_obj.name, 'error': error}
                )

        return errors