Beispiel #1
0
    def _ep_data(self, ep_obj):
        # type: (sickbeard.tv.TVEpisode) -> Optional[Union[bool, etree.Element]]
        """
        Creates an elementTree XML structure for an XBMC-style episode.nfo and
        returns the resulting data object.
            show_obj: a TVEpisode instance to create the NFO for
        """

        ep_obj_list_to_write = [ep_obj] + ep_obj.related_ep_obj

        show_lang = ep_obj.show_obj.lang

        tvinfo_config = sickbeard.TVInfoAPI(
            ep_obj.show_obj.tvid).api_params.copy()

        tvinfo_config['actors'] = True

        if show_lang and not 'en' == show_lang:
            tvinfo_config['language'] = show_lang

        if 0 != ep_obj.show_obj.dvdorder:
            tvinfo_config['dvdorder'] = True

        try:
            t = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).setup(**tvinfo_config)
            show_info = t[ep_obj.show_obj.prodid]
        except BaseTVinfoShownotfound as e:
            raise exceptions_helper.ShowNotFoundException(ex(e))
        except BaseTVinfoError as e:
            logger.log(
                'Unable to connect to %s while creating meta files - skipping - %s'
                % (sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name, ex(e)),
                logger.ERROR)
            return

        if not self._valid_show(show_info, ep_obj.show_obj):
            return

        if 1 < len(ep_obj_list_to_write):
            rootNode = etree.Element('xbmcmultiepisode')
        else:
            rootNode = etree.Element('episodedetails')

        # write an NFO containing info for all matching episodes
        for cur_ep_obj in ep_obj_list_to_write:

            try:
                ep_info = show_info[cur_ep_obj.season][cur_ep_obj.episode]
            except (BaseTVinfoEpisodenotfound, BaseTVinfoSeasonnotfound) as e:
                logger.log(
                    'Unable to find episode %sx%s on %s.. has it been removed? Should I delete from db?'
                    % (cur_ep_obj.season, cur_ep_obj.episode,
                       sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name))
                return None
            except (BaseException, Exception):
                logger.log(
                    u'Not generating nfo because failed to fetched tv info data at this time',
                    logger.DEBUG)
                return None

            if None is getattr(ep_info, 'firstaired', None):
                ep_info['firstaired'] = str(datetime.date.fromordinal(1))

            if None is getattr(ep_info, 'episodename', None):
                logger.log(u'Not generating nfo because the ep has no title',
                           logger.DEBUG)
                return None

            logger.log(
                u'Creating metadata for episode ' + str(ep_obj.season) + 'x' +
                str(ep_obj.episode), logger.DEBUG)

            if 1 < len(ep_obj_list_to_write):
                episode = etree.SubElement(rootNode, 'episodedetails')
            else:
                episode = rootNode

            title = etree.SubElement(episode, 'title')
            if None is not cur_ep_obj.name:
                title.text = '%s' % cur_ep_obj.name

            showtitle = etree.SubElement(episode, 'showtitle')
            if None is not cur_ep_obj.show_obj.name:
                showtitle.text = '%s' % cur_ep_obj.show_obj.name

            season = etree.SubElement(episode, 'season')
            season.text = str(cur_ep_obj.season)

            episodenum = etree.SubElement(episode, 'episode')
            episodenum.text = str(cur_ep_obj.episode)

            uniqueid = etree.SubElement(episode, 'uniqueid')
            uniqueid.text = str(cur_ep_obj.epid)

            aired = etree.SubElement(episode, 'aired')
            if cur_ep_obj.airdate != datetime.date.fromordinal(1):
                aired.text = str(cur_ep_obj.airdate)
            else:
                aired.text = ''

            plot = etree.SubElement(episode, 'plot')
            if None is not cur_ep_obj.description:
                plot.text = '%s' % cur_ep_obj.description

            runtime = etree.SubElement(episode, 'runtime')
            if 0 != cur_ep_obj.season:
                if None is not getattr(show_info, 'runtime', None):
                    runtime.text = '%s' % show_info['runtime']

            displayseason = etree.SubElement(episode, 'displayseason')
            if None is not getattr(ep_info, 'airsbefore_season', None):
                displayseason_text = ep_info['airsbefore_season']
                if None is not displayseason_text:
                    displayseason.text = '%s' % displayseason_text

            displayepisode = etree.SubElement(episode, 'displayepisode')
            if None is not getattr(ep_info, 'airsbefore_episode', None):
                displayepisode_text = ep_info['airsbefore_episode']
                if None is not displayepisode_text:
                    displayepisode.text = '%s' % displayepisode_text

            thumb = etree.SubElement(episode, 'thumb')
            thumb_text = getattr(ep_info, 'filename', None)
            if None is not thumb_text:
                thumb.text = '%s' % thumb_text

            watched = etree.SubElement(episode, 'watched')
            watched.text = 'false'

            credits = etree.SubElement(episode, 'credits')
            credits_text = getattr(ep_info, 'writer', None)
            if None is not credits_text:
                credits.text = '%s' % credits_text

            director = etree.SubElement(episode, 'director')
            director_text = getattr(ep_info, 'director', None)
            if None is not director_text:
                director.text = '%s' % director_text

            rating = etree.SubElement(episode, 'rating')
            rating_text = getattr(ep_info, 'rating', None)
            if None is not rating_text:
                rating.text = '%s' % rating_text

            gueststar_text = getattr(ep_info, 'gueststars', None)
            if isinstance(gueststar_text, string_types):
                for actor in (x.strip() for x in gueststar_text.split('|')
                              if x.strip()):
                    cur_actor = etree.SubElement(episode, 'actor')
                    cur_actor_name = etree.SubElement(cur_actor, 'name')
                    cur_actor_name.text = '%s' % actor

            self.add_actor_element(show_info, etree, episode)

        # Make it purdy
        sg_helpers.indent_xml(rootNode)

        data = etree.ElementTree(rootNode)

        return data
Beispiel #2
0
    def _ep_data(self, ep_obj):
        # type: (sickbeard.tv.TVEpisode) -> Optional[Union[bool, etree.Element]]
        """
        Creates an elementTree XML structure for a WDTV style episode.xml
        and returns the resulting data object.

        ep_obj: a TVShow instance to create the NFO for
        """

        ep_obj_list_to_write = [ep_obj] + ep_obj.related_ep_obj

        show_lang = ep_obj.show_obj.lang

        try:
            tvinfo_config = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).api_params.copy()

            tvinfo_config['actors'] = True

            if show_lang and not 'en' == show_lang:
                tvinfo_config['language'] = show_lang

            if 0 != ep_obj.show_obj.dvdorder:
                tvinfo_config['dvdorder'] = True

            t = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).setup(**tvinfo_config)
            show_info = t[ep_obj.show_obj.prodid]
        except BaseTVinfoShownotfound as e:
            raise exceptions_helper.ShowNotFoundException(ex(e))
        except BaseTVinfoError as e:
            logger.log(
                "Unable to connect to %s while creating meta files - skipping - %s"
                % (sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name, ex(e)),
                logger.ERROR)
            return False

        if not self._valid_show(show_info, ep_obj.show_obj):
            return

        rootNode = etree.Element("details")
        data = None

        # write an WDTV XML containing info for all matching episodes
        for cur_ep_obj in ep_obj_list_to_write:

            try:
                ep_info = show_info[cur_ep_obj.season][cur_ep_obj.episode]
            except (BaseException, Exception):
                logger.log(
                    "Unable to find episode %sx%s on %s... has it been removed? Should I delete from db?"
                    % (cur_ep_obj.season, cur_ep_obj.episode,
                       sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name))
                return None

            if None is getattr(ep_info, 'firstaired',
                               None) and 0 == ep_obj.season:
                ep_info["firstaired"] = str(datetime.date.fromordinal(1))

            if None is getattr(ep_info, 'episodename',
                               None) or None is getattr(
                                   ep_info, 'firstaired', None):
                return None

            if 1 < len(ep_obj_list_to_write):
                episode = etree.SubElement(rootNode, "details")
            else:
                episode = rootNode

            episodeID = etree.SubElement(episode, "id")
            episodeID.text = str(cur_ep_obj.epid)

            title = etree.SubElement(episode, "title")
            title.text = '%s' % ep_obj.pretty_name()

            seriesName = etree.SubElement(episode, "series_name")
            if None is not getattr(show_info, 'seriesname', None):
                seriesName.text = '%s' % show_info["seriesname"]

            episodeName = etree.SubElement(episode, "episode_name")
            if None is not cur_ep_obj.name:
                episodeName.text = '%s' % cur_ep_obj.name

            seasonNumber = etree.SubElement(episode, "season_number")
            seasonNumber.text = str(cur_ep_obj.season)

            episodeNum = etree.SubElement(episode, "episode_number")
            episodeNum.text = str(cur_ep_obj.episode)

            firstAired = etree.SubElement(episode, "firstaired")

            if cur_ep_obj.airdate != datetime.date.fromordinal(1):
                firstAired.text = str(cur_ep_obj.airdate)

            year = etree.SubElement(episode, "year")
            year_text = self.get_show_year(ep_obj.show_obj, show_info)
            if year_text:
                year.text = '%s' % year_text

            runtime = etree.SubElement(episode, "runtime")
            if 0 != cur_ep_obj.season:
                if None is not getattr(show_info, 'runtime', None):
                    runtime.text = '%s' % show_info["runtime"]

            genre = etree.SubElement(episode, "genre")
            if None is not getattr(show_info, 'genre', None):
                genre.text = " / ".join(
                    [x for x in show_info["genre"].split('|') if x])

            director = etree.SubElement(episode, "director")
            director_text = getattr(ep_info, 'director', None)
            if None is not director_text:
                director.text = '%s' % director_text

            for actor in getattr(show_info, 'actors', []):
                cur_actor = etree.SubElement(episode, 'actor')

                cur_actor_name = etree.SubElement(cur_actor, 'name')
                cur_actor_name.text = '%s' % actor['person']['name']

                cur_actor_role = etree.SubElement(cur_actor, 'role')
                cur_actor_role_text = '%s' % actor['character']['name']
                if cur_actor_role_text:
                    cur_actor_role.text = '%s' % cur_actor_role_text

            overview = etree.SubElement(episode, "overview")
            if None is not cur_ep_obj.description:
                overview.text = '%s' % cur_ep_obj.description

            # Make it purdy
            sg_helpers.indent_xml(rootNode)
            data = etree.ElementTree(rootNode)

        return data
Beispiel #3
0
    def _ep_data(self, ep_obj):
        # type: (sickbeard.tv.TVEpisode) -> Optional[Union[bool, etree.Element]]
        """
        Creates an elementTree XML structure for a MediaBrowser style episode.xml
        and returns the resulting data object.

        show_obj: a TVShow instance to create the NFO for
        """

        ep_obj_list_to_write = [ep_obj] + ep_obj.related_ep_obj

        show_lang = ep_obj.show_obj.lang

        try:
            # There's gotta be a better way of doing this but we don't wanna
            # change the language value elsewhere
            tvinfo_config = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).api_params.copy()

            if show_lang and not 'en' == show_lang:
                tvinfo_config['language'] = show_lang

            if 0 != ep_obj.show_obj.dvdorder:
                tvinfo_config['dvdorder'] = True

            t = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).setup(**tvinfo_config)
            show_info = t[ep_obj.show_obj.prodid]
        except BaseTVinfoShownotfound as e:
            raise exceptions_helper.ShowNotFoundException(ex(e))
        except BaseTVinfoError as e:
            logger.log(
                'Unable to connect to %s while creating meta files - skipping - %s'
                % (sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name, ex(e)),
                logger.ERROR)
            return False

        if not self._valid_show(show_info, ep_obj.show_obj):
            return

        rootNode = etree.Element('details')
        movie = etree.SubElement(rootNode, 'movie')

        movie.attrib['isExtra'] = 'false'
        movie.attrib['isSet'] = 'false'
        movie.attrib['isTV'] = 'true'

        # write an MediaBrowser XML containing info for all matching episodes
        for cur_ep_obj in ep_obj_list_to_write:

            try:
                ep_info = show_info[cur_ep_obj.season][cur_ep_obj.episode]
            except (BaseException, Exception):
                logger.log(
                    u'Unable to find episode %sx%s on tvdb... has it been removed? Should I delete from db?'
                    % (cur_ep_obj.season, cur_ep_obj.episode))
                return None

            if cur_ep_obj == ep_obj:
                # root (or single) episode

                # default to today's date for specials if firstaired is not set
                if None is ep_info['firstaired'] and 0 == ep_obj.season:
                    ep_info['firstaired'] = str(datetime.date.fromordinal(1))

                if None is ep_info['episodename'] or None is ep_info[
                        'firstaired']:
                    return None

                episode = movie

                EpisodeName = etree.SubElement(episode, 'title')
                if None is not cur_ep_obj.name:
                    EpisodeName.text = '%s' % cur_ep_obj.name
                else:
                    EpisodeName.text = ''

                SeasonNumber = etree.SubElement(episode, 'season')
                SeasonNumber.text = str(cur_ep_obj.season)

                EpisodeNumber = etree.SubElement(episode, 'episode')
                EpisodeNumber.text = str(ep_obj.episode)

                year = etree.SubElement(episode, 'year')
                year_text = self.get_show_year(ep_obj.show_obj, show_info)
                if year_text:
                    year.text = '%s' % year_text

                plot = etree.SubElement(episode, 'plot')
                if None is not show_info['overview']:
                    plot.text = '%s' % show_info['overview']

                Overview = etree.SubElement(episode, 'episodeplot')
                if None is not cur_ep_obj.description:
                    Overview.text = '%s' % cur_ep_obj.description
                else:
                    Overview.text = ''

                mpaa = etree.SubElement(episode, 'mpaa')
                if None is not show_info['contentrating']:
                    mpaa.text = '%s' % show_info['contentrating']

                if not ep_obj.related_ep_obj:
                    if None is not ep_info['rating']:
                        try:
                            rating = int((float(ep_info['rating']) * 10))
                        except ValueError:
                            rating = 0
                        Rating = etree.SubElement(episode, 'rating')
                        rating_text = str(rating)
                        if None is not rating_text:
                            Rating.text = '%s' % rating_text

                director = etree.SubElement(episode, 'director')
                director_text = ep_info['director']
                if None is not director_text:
                    director.text = '%s' % director_text

                credits = etree.SubElement(episode, 'credits')
                credits_text = ep_info['writer']
                if None is not credits_text:
                    credits.text = '%s' % credits_text

                cast = etree.SubElement(episode, 'cast')
                self.add_actor_element(show_info, etree, cast)

            else:
                # append data from (if any) related episodes

                if cur_ep_obj.name:
                    if not EpisodeName.text:
                        EpisodeName.text = '%s' % cur_ep_obj.name
                    else:
                        EpisodeName.text = '%s, %s' % (EpisodeName.text,
                                                       cur_ep_obj.name)

                if cur_ep_obj.description:
                    if not Overview.text:
                        Overview.text = '%s' % cur_ep_obj.description
                    else:
                        Overview.text = '%s\r%s' % (Overview.text,
                                                    cur_ep_obj.description)

        sg_helpers.indent_xml(rootNode)
        data = etree.ElementTree(rootNode)

        return data
Beispiel #4
0
    def _ep_data(self, ep_obj):
        # type: (sickbeard.tv.TVEpisode) -> Optional[Union[bool, etree.Element]]
        """
        Creates an elementTree XML structure for a MediaBrowser style episode.xml
        and returns the resulting data object.

        show_obj: a TVShow instance to create the NFO for
        """

        ep_obj_list_to_write = [ep_obj] + ep_obj.related_ep_obj

        persons_dict = {'Director': [], 'GuestStar': [], 'Writer': []}

        show_lang = ep_obj.show_obj.lang

        try:
            tvinfo_config = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).api_params.copy()

            tvinfo_config['actors'] = True

            if show_lang and not 'en' == show_lang:
                tvinfo_config['language'] = show_lang

            if 0 != ep_obj.show_obj.dvdorder:
                tvinfo_config['dvdorder'] = True

            t = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).setup(**tvinfo_config)

            show_info = t[ep_obj.show_obj.prodid]
        except Exception as e:
            if check_exception_type(e, ExceptionTuples.tvinfo_shownotfound):
                raise exceptions_helper.ShowNotFoundException(ex(e))
            elif check_exception_type(e, ExceptionTuples.tvinfo_error):
                logger.log(
                    "Unable to connect to %s while creating meta files - skipping - %s"
                    % (sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name, ex(e)),
                    logger.ERROR)
                return False
            else:
                raise e

        if not self._valid_show(show_info, ep_obj.show_obj):
            return

        rootNode = etree.Element("Item")

        # write an MediaBrowser XML containing info for all matching episodes
        for cur_ep_obj in ep_obj_list_to_write:

            try:
                ep_info = show_info[cur_ep_obj.season][cur_ep_obj.episode]
            except (BaseException, Exception):
                logger.log(
                    "Unable to find episode %sx%s on %s.. has it been removed? Should I delete from db?"
                    % (cur_ep_obj.season, cur_ep_obj.episode,
                       sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name))
                return None

            if cur_ep_obj == ep_obj:
                # root (or single) episode

                # default to today's date for specials if firstaired is not set
                if None is getattr(ep_info, 'firstaired',
                                   None) and 0 == ep_obj.season:
                    ep_info['firstaired'] = str(datetime.date.fromordinal(1))

                if None is getattr(ep_info, 'episodename',
                                   None) or None is getattr(
                                       ep_info, 'firstaired', None):
                    return None

                episode = rootNode

                EpisodeName = etree.SubElement(episode, "EpisodeName")
                if None is not cur_ep_obj.name:
                    EpisodeName.text = '%s' % cur_ep_obj.name
                else:
                    EpisodeName.text = ""

                EpisodeNumber = etree.SubElement(episode, "EpisodeNumber")
                EpisodeNumber.text = str(ep_obj.episode)

                if ep_obj.related_ep_obj:
                    EpisodeNumberEnd = etree.SubElement(
                        episode, "EpisodeNumberEnd")
                    EpisodeNumberEnd.text = str(cur_ep_obj.episode)

                SeasonNumber = etree.SubElement(episode, "SeasonNumber")
                SeasonNumber.text = str(cur_ep_obj.season)

                if not ep_obj.related_ep_obj:
                    absolute_number = etree.SubElement(episode,
                                                       "absolute_number")
                    if None is not getattr(ep_info, 'absolute_number', None):
                        absolute_number.text = '%s' % ep_info['absolute_number']

                FirstAired = etree.SubElement(episode, "FirstAired")
                if cur_ep_obj.airdate != datetime.date.fromordinal(1):
                    FirstAired.text = str(cur_ep_obj.airdate)
                else:
                    FirstAired.text = ""

                MetadataType = etree.SubElement(episode, "Type")
                MetadataType.text = "Episode"

                Overview = etree.SubElement(episode, "Overview")
                if None is not cur_ep_obj.description:
                    Overview.text = '%s' % cur_ep_obj.description
                else:
                    Overview.text = ""

                if not ep_obj.related_ep_obj:
                    Rating = etree.SubElement(episode, "Rating")
                    if None is not getattr(ep_info, 'rating', None):
                        Rating.text = '%s' % ep_info['rating']

                    IMDB_ID = etree.SubElement(episode, "IMDB_ID")
                    IMDB = etree.SubElement(episode, "IMDB")
                    IMDbId = etree.SubElement(episode, "IMDbId")
                    if None is not getattr(show_info, 'imdb_id', None):
                        IMDB_ID.text = '%s' % show_info['imdb_id']
                        IMDB.text = '%s' % show_info['imdb_id']
                        IMDbId.text = '%s' % show_info['imdb_id']

                prodid = etree.SubElement(episode, "id")
                prodid.text = str(cur_ep_obj.show_obj.prodid)

                tvid = etree.SubElement(episode, "indexer")
                tvid.text = str(cur_ep_obj.show_obj.tvid)

                Persons = etree.SubElement(episode, "Persons")

                Language = etree.SubElement(episode, "Language")
                try:
                    Language.text = '%s' % cur_ep_obj.show_obj.lang
                except (BaseException, Exception):
                    Language.text = 'en'  # tvrage api doesn't provide language so we must assume a value here

                thumb = etree.SubElement(episode, "filename")
                # TODO: See what this is needed for.. if its still needed
                # just write this to the NFO regardless of whether it actually exists or not
                # note: renaming files after nfo generation will break this, tough luck
                thumb_text = self.get_episode_thumb_path(ep_obj)
                if thumb_text:
                    thumb.text = '%s' % thumb_text

            else:
                # append data from (if any) related episodes
                EpisodeNumberEnd.text = str(cur_ep_obj.episode)

                if cur_ep_obj.name:
                    if not EpisodeName.text:
                        EpisodeName.text = '%s' % cur_ep_obj.name
                    else:
                        EpisodeName.text = '%s, %s' % (EpisodeName.text,
                                                       cur_ep_obj.name)

                if cur_ep_obj.description:
                    if not Overview.text:
                        Overview.text = '%s' % cur_ep_obj.description
                    else:
                        Overview.text = '%s\r%s' % (Overview.text,
                                                    cur_ep_obj.description)

            # collect all directors, guest stars and writers
            if None is not getattr(ep_info, 'director', None):
                persons_dict['Director'] += [
                    x.strip() for x in ep_info['director'].split('|') if x
                ]
            if None is not getattr(ep_info, 'gueststars', None):
                persons_dict['GuestStar'] += [
                    x.strip() for x in ep_info['gueststars'].split('|') if x
                ]
            if None is not getattr(ep_info, 'writer', None):
                persons_dict['Writer'] += [
                    x.strip() for x in ep_info['writer'].split('|') if x
                ]

        # fill in Persons section with collected directors, guest starts and writers
        for person_type, names in iteritems(persons_dict):
            # remove doubles
            names = list(set(names))
            for cur_name in names:
                Person = etree.SubElement(Persons, "Person")
                cur_person_name = etree.SubElement(Person, "Name")
                cur_person_name.text = '%s' % cur_name
                cur_person_type = etree.SubElement(Person, "Type")
                cur_person_type.text = '%s' % person_type

        helpers.indent_xml(rootNode)
        data = etree.ElementTree(rootNode)

        return data
Beispiel #5
0
    def _ep_data(self, ep_obj):
        # type: (sickbeard.tv.TVEpisode) -> Optional[Union[bool, AnyStr]]
        """
        Creates a key value structure for a Tivo episode metadata file and
        returns the resulting data object.

        ep_obj: a TVEpisode instance to create the metadata file for.

        Lookup the show in http://thetvdb.com/ using the python library:

        https://github.com/dbr/indexer_api/

        The results are saved in the object show_info.

        The key values for the tivo metadata file are from:

        http://pytivo.sourceforge.net/wiki/index.php/Metadata
        """

        data = ''

        ep_obj_list_to_write = [ep_obj] + ep_obj.related_ep_obj

        show_lang = ep_obj.show_obj.lang

        try:
            tvinfo_config = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).api_params.copy()

            tvinfo_config['actors'] = True

            if show_lang and not 'en' == show_lang:
                tvinfo_config['language'] = show_lang

            if 0 != ep_obj.show_obj.dvdorder:
                tvinfo_config['dvdorder'] = True

            t = sickbeard.TVInfoAPI(
                ep_obj.show_obj.tvid).setup(**tvinfo_config)
            show_info = t[ep_obj.show_obj.prodid]
        except BaseTVinfoShownotfound as e:
            raise exceptions_helper.ShowNotFoundException(ex(e))
        except BaseTVinfoError as e:
            logger.log(
                "Unable to connect to %s while creating meta files - skipping - %s"
                % (sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name, ex(e)),
                logger.ERROR)
            return False

        if not self._valid_show(show_info, ep_obj.show_obj):
            return

        for cur_ep_obj in ep_obj_list_to_write:

            try:
                ep_info = show_info[cur_ep_obj.season][cur_ep_obj.episode]
            except (BaseException, Exception):
                logger.log(
                    "Unable to find episode %sx%s on %s... has it been removed? Should I delete from db?"
                    % (cur_ep_obj.season, cur_ep_obj.episode,
                       sickbeard.TVInfoAPI(ep_obj.show_obj.tvid).name))
                return None

            if None is getattr(ep_info, 'firstaired',
                               None) and 0 == ep_obj.season:
                ep_info["firstaired"] = str(datetime.date.fromordinal(1))

            if None is getattr(ep_info, 'episodename',
                               None) or None is getattr(
                                   ep_info, 'firstaired', None):
                return None

            if None is not getattr(show_info, 'seriesname', None):
                data += ("title : " + show_info["seriesname"] + "\n")
                data += ("seriesTitle : " + show_info["seriesname"] + "\n")

            data += ("episodeTitle : " +
                     cur_ep_obj._format_pattern('%Sx%0E %EN') + "\n")

            # This should be entered for episodic shows and omitted for movies. The standard tivo format is to enter
            # the season number followed by the episode number for that season. For example, enter 201 for season 2
            # episode 01.

            # This only shows up if you go into the Details from the Program screen.

            # This seems to disappear once the video is transferred to TiVo.

            # NOTE: May not be correct format, missing season, but based on description from wiki leaving as is.
            data += ("episodeNumber : " + str(cur_ep_obj.episode) + "\n")

            # Must be entered as true or false. If true, the year from originalAirDate will be shown in parentheses
            # after the episode's title and before the description on the Program screen.

            # FIXME: Hardcode isEpisode to true for now, not sure how to handle movies
            data += "isEpisode : true\n"

            # Write the synopsis of the video here
            # Micrsoft Word's smartquotes can die in a fire.
            sanitizedDescription = cur_ep_obj.description
            # Replace double curly quotes
            sanitizedDescription = sanitizedDescription.replace(
                u"\u201c", "\"").replace(u"\u201d", "\"")
            # Replace single curly quotes
            sanitizedDescription = sanitizedDescription.replace(
                u"\u2018", "'").replace(u"\u2019",
                                        "'").replace(u"\u02BC", "'")

            data += ("description : " + sanitizedDescription + "\n")

            # Usually starts with "SH" and followed by 6-8 digits.
            # Tivo uses zap2it for thier data, so the series id is the zap2it_id.
            if None is not getattr(show_info, 'zap2it_id', None):
                data += ("seriesId : " + show_info["zap2it_id"] + "\n")

            # This is the call sign of the channel the episode was recorded from.
            if None is not getattr(show_info, 'network', None):
                data += ("callsign : " + show_info["network"] + "\n")

            # This must be entered as yyyy-mm-ddThh:mm:ssZ (the t is capitalized and never changes, the Z is also
            # capitalized and never changes). This is the original air date of the episode.
            # NOTE: Hard coded the time to T00:00:00Z as we really don't know when during the day the first run happened
            if cur_ep_obj.airdate != datetime.date.fromordinal(1):
                data += ("originalAirDate : " + str(cur_ep_obj.airdate) +
                         "T00:00:00Z\n")

            # This shows up at the beginning of the description on the Program screen and on the Details screen.
            for actor in getattr(show_info, 'actors', []):
                data += ('vActor : %s\n' % actor['character']['name']
                         and actor['person']['name'] and
                         actor['character']['name'] != actor['person']['name']
                         and '%s (%s)' %
                         (actor['character']['name'], actor['person']['name'])
                         or actor['person']['name']
                         or actor['character']['name'])

            # This is shown on both the Program screen and the Details screen.
            if None is not getattr(ep_info, 'rating', None):
                try:
                    rating = float(ep_info['rating'])
                except ValueError:
                    rating = 0.0
                # convert 10 to 4 star rating. 4 * rating / 10
                # only whole numbers or half numbers work. multiply by 2, round, divide by 2.0
                rating = round(8 * rating / 10) / 2.0
                data += ("starRating : " + str(rating) + "\n")

            # This is shown on both the Program screen and the Details screen.
            # It uses the standard TV rating system of: TV-Y7, TV-Y, TV-G, TV-PG, TV-14, TV-MA and TV-NR.
            if None is not getattr(show_info, 'contentrating', None):
                data += ("tvRating : " + str(show_info["contentrating"]) +
                         "\n")

            # This field can be repeated as many times as necessary or omitted completely.
            if ep_obj.show_obj.genre:
                for genre in ep_obj.show_obj.genre.split('|'):
                    if genre:
                        data += ("vProgramGenre : " + str(genre) + "\n")

                        # NOTE: The following are metadata keywords are not used
                        # displayMajorNumber
                        # showingBits
                        # displayMinorNumber
                        # colorCode
                        # vSeriesGenre
                        # vGuestStar, vDirector, vExecProducer, vProducer, vWriter, vHost, vChoreographer
                        # partCount
                        # partIndex

        return data