def show_tvguide(self, date=None, channel=None):
        """Offer a menu depending on the information provided"""

        if not date and not channel:
            date_items = self.get_date_items()
            show_listing(date_items, category=30026,
                         content='files')  # TV guide

        elif not channel:
            channel_items = self.get_channel_items(date=date)
            entry = find_entry(RELATIVE_DATES, 'id', date)
            date_name = localize(entry.get('msgctxt')) if entry else date
            show_listing(channel_items, category=date_name)

        elif not date:
            date_items = self.get_date_items(channel=channel)
            channel_name = find_entry(CHANNELS, 'name', channel).get('label')
            show_listing(date_items,
                         category=channel_name,
                         content='files',
                         selected=7)

        else:
            episode_items = self.get_episode_items(date, channel)
            channel_name = find_entry(CHANNELS, 'name', channel).get('label')
            entry = find_entry(RELATIVE_DATES, 'id', date)
            date_name = localize(entry.get('msgctxt')) if entry else date
            show_listing(episode_items,
                         category='%s / %s' % (channel_name, date_name),
                         content='episodes',
                         cache=False)
    def get_epg_data(self):
        """Return EPG data"""
        now = datetime.now(dateutil.tz.tzlocal())

        epg_data = {}
        for date in ['yesterday', 'today', 'tomorrow']:
            epg = self.parse(date, now)
            epg_url = epg.strftime(self.VRT_TVGUIDE)
            schedule = get_url_json(url=epg_url, fail={})
            for channel_id, episodes in list(schedule.items()):
                channel = find_entry(CHANNELS, 'id', channel_id)
                epg_id = channel.get('epg_id')
                if epg_id not in epg_data:
                    epg_data[epg_id] = []
                for episode in episodes:
                    if episode.get('url') and episode.get('vrt.whatson-id'):
                        path = url_for(
                            'play_whatson_id',
                            whatson_id=episode.get('vrt.whatson-id'))
                    else:
                        path = None
                    epg_data[epg_id].append(
                        dict(
                            start=episode.get('startTime'),
                            stop=episode.get('endTime'),
                            image=add_https_proto(episode.get('image', '')),
                            title=episode.get('title'),
                            subtitle=html_to_kodi(episode.get('subtitle', '')),
                            description=html_to_kodi(
                                episode.get('description', '')),
                            stream=path,
                        ))
        return epg_data
    def playing_now(self, channel):
        """Return the EPG information for what is playing now"""
        now = datetime.now(dateutil.tz.tzlocal())
        epg = now
        # Daily EPG information shows information from 6AM until 6AM
        if epg.hour < 6:
            epg += timedelta(days=-1)

        entry = find_entry(CHANNELS, 'name', channel)
        if not entry:
            return ''

        epg_url = epg.strftime(self.VRT_TVGUIDE)
        schedule = get_cached_url_json(url=epg_url,
                                       cache='schedule.today.json',
                                       ttl=ttl('indirect'),
                                       fail={})
        episodes = iter(schedule.get(entry.get('id'), []))

        while True:
            try:
                episode = next(episodes)
            except StopIteration:
                break
            start_date = dateutil.parser.parse(episode.get('startTime'))
            end_date = dateutil.parser.parse(episode.get('endTime'))
            if start_date <= now <= end_date:  # Now playing
                return episode.get('title')
        return ''
Exemple #4
0
    def get_episode_items(self, date, channel):
        """Show episodes for a given date and channel"""
        now = datetime.now(dateutil.tz.tzlocal())
        epg = self.parse(date, now)
        epg_url = epg.strftime(self.VRT_TVGUIDE)

        self._favorites.refresh(ttl=ttl('indirect'))
        self._resumepoints.refresh(ttl=ttl('indirect'))

        cache_file = 'schedule.{date}.json'.format(date=date)
        if date in ('today', 'yesterday', 'tomorrow'):
            schedule = get_cached_url_json(url=epg_url,
                                           cache=cache_file,
                                           ttl=ttl('indirect'),
                                           fail={})
        else:
            schedule = get_url_json(url=epg_url, fail={})

        entry = find_entry(CHANNELS, 'name', channel)
        if entry:
            episodes = schedule.get(entry.get('id'), [])
        else:
            episodes = []
        episode_items = []
        for episode in episodes:
            program = url_to_program(episode.get('url', ''))
            if episode.get('url'):
                video_url = add_https_proto(episode.get('url'))
                path = url_for('play_url', video_url=video_url)
                context_menu, favorite_marker, watchlater_marker = self._metadata.get_context_menu(
                    episode, program, cache_file)
                label = self._metadata.get_label(
                    episode) + favorite_marker + watchlater_marker
                is_playable = True
            else:
                label = '[COLOR={greyedout}]%s[/COLOR]' % self._metadata.get_label(
                    episode)
                path = url_for('noop')
                context_menu, _, _ = self._metadata.get_context_menu(
                    episode, program, cache_file)
                is_playable = False

            info_labels = self._metadata.get_info_labels(episode,
                                                         date=date,
                                                         channel=entry)
            # FIXME: Due to a bug in Kodi, ListItem.Title is used when Sort methods are used, not ListItem.Label
            info_labels['title'] = colour(label)

            episode_items.append(
                TitleItem(
                    label=colour(label),
                    path=path,
                    art_dict=self._metadata.get_art(episode),
                    info_dict=info_labels,
                    context_menu=context_menu,
                    is_playable=is_playable,
                ))
        return episode_items
 def show_featured_menu(self, feature=None):
     """The VRT NU add-on 'Featured content' listing menu"""
     if feature:
         self._favorites.refresh(ttl=ttl('indirect'))
         self._resumepoints.refresh(ttl=ttl('indirect'))
         tvshow_items = self._apihelper.list_tvshows(feature=feature)
         from data import FEATURED
         feature_msgctxt = find_entry(FEATURED, 'id', feature).get('msgctxt')
         show_listing(tvshow_items, category=feature_msgctxt, sort='label', content='tvshows', cache=False)
     else:
         featured_items = self._apihelper.list_featured()
         show_listing(featured_items, category=30024, sort='label', content='files')
 def show_category_menu(self, category=None):
     """The VRT NU add-on 'Categories' listing menu"""
     if category:
         self._favorites.refresh(ttl=ttl('indirect'))
         self._resumepoints.refresh(ttl=ttl('indirect'))
         tvshow_items = self._apihelper.list_tvshows(category=category)
         from data import CATEGORIES
         category_msgctxt = find_entry(CATEGORIES, 'id', category).get('msgctxt')
         show_listing(tvshow_items, category=category_msgctxt, sort='label', content='tvshows')
     else:
         category_items = self._apihelper.list_categories()
         show_listing(category_items, category=30014, sort='unsorted', content='files')  # Categories
    def live_description(self, channel):
        """Return the EPG information for current and next live program"""
        now = datetime.now(dateutil.tz.tzlocal())
        epg = now
        # Daily EPG information shows information from 6AM until 6AM
        if epg.hour < 6:
            epg += timedelta(days=-1)

        entry = find_entry(CHANNELS, 'name', channel)
        if not entry:
            return ''

        epg_url = epg.strftime(self.VRT_TVGUIDE)
        schedule = get_cached_url_json(url=epg_url,
                                       cache='schedule.today.json',
                                       ttl=ttl('indirect'),
                                       fail={})
        episodes = iter(schedule.get(entry.get('id'), []))

        description = ''
        episode = None
        while True:
            try:
                episode = next(episodes)
            except StopIteration:
                break
            start_date = dateutil.parser.parse(episode.get('startTime'))
            end_date = dateutil.parser.parse(episode.get('endTime'))
            if start_date <= now <= end_date:  # Now playing
                description = '[COLOR={highlighted}][B]%s[/B] %s[/COLOR]\n' % (
                    localize(30421), self.episode_description(episode))
                try:
                    description += '[B]%s[/B] %s' % (localize(30422),
                                                     self.episode_description(
                                                         next(episodes)))
                except StopIteration:
                    break
                break
            if now < start_date:  # Nothing playing now, but this may be next
                description = '[B]%s[/B] %s\n' % (
                    localize(30422), self.episode_description(episode))
                try:
                    description += '[B]%s[/B] %s' % (localize(30422),
                                                     self.episode_description(
                                                         next(episodes)))
                except StopIteration:
                    break
                break
        if episode and not description:
            # Add a final 'No transmission' program
            description = '[COLOR={highlighted}][B]%s[/B] %s - 06:00\n» %s[/COLOR]' % (
                localize(30421), episode.get('end'), localize(30423))
        return colour(description)
    def parse(date, now):
        """Parse a given string and return a datetime object
            This supports 'today', 'yesterday' and 'tomorrow'
            It also compensates for TV-guides covering from 6AM to 6AM
       """
        entry = find_entry(RELATIVE_DATES, 'id', date)
        if not entry:
            return dateutil.parser.parse(date)

        offset = entry.get('offset')
        if now.hour < 6:
            return now + timedelta(days=offset - 1)

        return now + timedelta(days=offset)
    def get_date_items(channel=None):
        """Offer a menu to select the TV-guide date"""

        epg = datetime.now(dateutil.tz.tzlocal())
        # Daily EPG information shows information from 6AM until 6AM
        if epg.hour < 6:
            epg += timedelta(days=-1)
        date_items = []
        for offset in range(14, -19, -1):
            day = epg + timedelta(days=offset)
            label = localize_datelong(day)
            date = day.strftime('%Y-%m-%d')

            # Highlight today with context of 2 days
            entry = find_entry(RELATIVE_DATES, 'offset', offset)
            if entry:
                date_name = localize(entry.get('msgctxt'))
                if entry.get('permalink'):
                    date = entry.get('id')
                if offset == 0:
                    label = '[COLOR={highlighted}][B]{name}[/B], {date}[/COLOR]'.format(
                        highlighted=themecolour('highlighted'),
                        name=date_name,
                        date=label)
                else:
                    label = '[B]{name}[/B], {date}'.format(name=date_name,
                                                           date=label)

            plot = '[B]{datelong}[/B]'.format(datelong=localize_datelong(day))

            # Show channel list or channel episodes
            if channel:
                path = url_for('tvguide', date=date, channel=channel)
            else:
                path = url_for('tvguide', date=date)

            cache_file = 'schedule.{date}.json'.format(date=date)
            date_items.append(
                TitleItem(
                    label=label,
                    path=path,
                    art_dict=dict(thumb='DefaultYear.png'),
                    info_dict=dict(plot=plot),
                    context_menu=[(
                        localize(30413),  # Refresh menu
                        'RunPlugin(%s)' %
                        url_for('delete_cache', cache_file=cache_file))],
                ))
        return date_items
 def show_channels_menu(self, channel=None):
     """The VRT NU add-on 'Channels' listing menu"""
     if channel:
         from tvguide import TVGuide
         self._favorites.refresh(ttl=ttl('indirect'))
         self._resumepoints.refresh(ttl=ttl('indirect'))
         channel_items = self._apihelper.list_channels(channels=[channel])  # Live TV
         channel_items.extend(TVGuide().get_channel_items(channel=channel))  # TV guide
         channel_items.extend(self._apihelper.list_youtube(channels=[channel]))  # YouTube
         channel_items.extend(self._apihelper.list_tvshows(channel=channel))  # TV shows
         from data import CHANNELS
         channel_name = find_entry(CHANNELS, 'name', channel).get('label')
         show_listing(channel_items, category=channel_name, sort='unsorted', content='tvshows', cache=False)  # Channel
     else:
         channel_items = self._apihelper.list_channels(live=False)
         show_listing(channel_items, category=30016, cache=False)
    def get_tag(api_data):
        """Return categories for a given episode"""

        # VRT NU Search API
        if api_data.get('type') == 'episode':
            from data import CATEGORIES
            return sorted([
                localize(
                    find_entry(CATEGORIES, 'id', category,
                               {}).get('msgctxt', category))
                for category in api_data.get('categories', [])
            ])

        # VRT NU Suggest API
        if api_data.get('type') == 'program':
            return ['Series']

        return []
 def show_featured_menu(self, feature=None):
     """The VRT NU add-on 'Featured content' listing menu"""
     if feature:
         self._favorites.refresh(ttl=ttl('indirect'))
         self._resumepoints.refresh(ttl=ttl('indirect'))
         programs = None
         sort = 'label'
         content = 'tvshows'
         ascending = True
         if feature.startswith('jcr_'):
             media = self._apihelper.get_featured_media_from_web(
                 feature.split('jcr_')[1])
             if media.get('mediatype') == 'episodes':
                 variety = 'featured.{name}'.format(name=media.get(
                     'name').strip().lower().replace(' ', '_'))
                 media_items, sort, ascending, content = self._apihelper.list_episodes(
                     whatson_id=media.get('medialist'), variety=variety)
             elif media.get('mediatype') == 'tvshows':
                 feature = None
                 media_items = self._apihelper.list_tvshows(
                     feature=feature, programs=media.get('medialist'))
         else:
             media_items = self._apihelper.list_tvshows(feature=feature,
                                                        programs=programs)
         from data import FEATURED
         feature_msgctxt = None
         feature = find_entry(FEATURED, 'id', feature)
         if feature:
             feature_msgctxt = feature.get('msgctxt')
         show_listing(media_items,
                      category=feature_msgctxt,
                      sort=sort,
                      ascending=ascending,
                      content=content,
                      cache=False)
     else:
         featured_items = self._apihelper.list_featured()
         show_listing(featured_items,
                      category=30024,
                      sort='label',
                      content='files')
Exemple #13
0
 def get_epg_data(self):
     """Return EPG data"""
     epg_data = dict()
     epg_url = self.WEEK_SCHEDULE
     schedule = get_url_json(
         url=epg_url,
         headers=dict(
             accept='application/vnd.epg.vrt.be.schedule_3.1+json'),
         fail={})
     for event in schedule.get('events', []):
         channel_id = event.get('channel', dict(code=None)).get('code')
         if channel_id is None:
             log(2,
                 'No channel code found in EPG event: {event}',
                 event=event)
             continue
         channel = find_entry(CHANNELS, 'id', channel_id)
         if channel is None:
             log(2, 'No channel found using code: {code}', code=channel_id)
             continue
         epg_id = channel.get('epg_id')
         if epg_id not in epg_data:
             epg_data[epg_id] = []
         if event.get('images'):
             image = event.get('images')[0].get('url')
         else:
             image = None
         epg_data[epg_id].append(
             dict(
                 start=event.get('startTime'),
                 stop=event.get('endTime'),
                 image=image,
                 title=event.get('title'),
                 description=html_to_kodi(event.get('description', '')),
             ))
     return epg_data
    def get_episode_items(self, date, channel):
        """Show episodes for a given date and channel"""
        now = datetime.now(dateutil.tz.tzlocal())
        epg = self.parse(date, now)
        epg_url = epg.strftime(self.VRT_TVGUIDE)

        self._favorites.refresh(ttl=ttl('indirect'))
        self._resumepoints.refresh(ttl=ttl('indirect'))

        cache_file = 'schedule.{date}.json'.format(date=date)
        if date in ('today', 'yesterday', 'tomorrow'):
            schedule = get_cached_url_json(url=epg_url,
                                           cache=cache_file,
                                           ttl=ttl('indirect'),
                                           fail={})
        else:
            schedule = get_url_json(url=epg_url, fail={})

        entry = find_entry(CHANNELS, 'name', channel)
        if entry:
            episodes = schedule.get(entry.get('id'), [])
        else:
            episodes = []
        episode_items = []
        for episode in episodes:
            program = url_to_program(episode.get('url', ''))
            context_menu, favorite_marker, watchlater_marker = self._metadata.get_context_menu(
                episode, program, cache_file)
            label = self._metadata.get_label(episode)
            path = self.get_episode_path(episode, channel)
            # Playable item
            if '/play/' in path:
                is_playable = True
                label += favorite_marker + watchlater_marker
            # Non-actionable item
            else:
                is_playable = False
                label = '[COLOR={greyedout}]%s[/COLOR]' % label

            # Now playing
            start_date = dateutil.parser.parse(episode.get('startTime'))
            end_date = dateutil.parser.parse(episode.get('endTime'))
            if start_date <= now <= end_date:
                if is_playable:
                    label = '[COLOR={highlighted}]%s[/COLOR] %s' % (
                        label, localize(30301))
                else:
                    label += localize(30301)

            info_labels = self._metadata.get_info_labels(episode,
                                                         date=date,
                                                         channel=entry)
            # FIXME: Due to a bug in Kodi, ListItem.Title is used when Sort methods are used, not ListItem.Label
            info_labels['title'] = colour(label)

            episode_items.append(
                TitleItem(
                    label=colour(label),
                    path=path,
                    art_dict=self._metadata.get_art(episode),
                    info_dict=info_labels,
                    context_menu=context_menu,
                    is_playable=is_playable,
                ))
        return episode_items
Exemple #15
0
    def get_episode_by_air_date(self, channel_name, start_date, end_date=None):
        """Get an episode of a program given the channel and the air date in iso format (2019-07-06T19:35:00)"""
        channel = find_entry(CHANNELS, 'name', channel_name)
        if not channel:
            return None

        from datetime import datetime, timedelta
        import dateutil.parser
        import dateutil.tz
        offairdate = None
        try:
            onairdate = dateutil.parser.parse(
                start_date,
                default=datetime.now(dateutil.tz.gettz('Europe/Brussels')))
        except ValueError:
            return None

        if end_date:
            try:
                offairdate = dateutil.parser.parse(
                    end_date,
                    default=datetime.now(dateutil.tz.gettz('Europe/Brussels')))
            except ValueError:
                return None
        video = None
        now = datetime.now(dateutil.tz.gettz('Europe/Brussels'))
        if onairdate.hour < 6:
            schedule_date = onairdate - timedelta(days=1)
        else:
            schedule_date = onairdate
        schedule_datestr = schedule_date.isoformat().split('T')[0]
        url = 'https://www.vrt.be/bin/epg/schedule.{date}.json'.format(
            date=schedule_datestr)
        schedule_json = get_url_json(url, fail={})
        episodes = schedule_json.get(channel.get('id'), [])
        if not episodes:
            return None

        # Guess the episode
        episode_guess = None
        if not offairdate:
            mindate = min(
                abs(onairdate -
                    dateutil.parser.parse(episode.get('startTime')))
                for episode in episodes)
            episode_guess = next((episode for episode in episodes if abs(
                onairdate -
                dateutil.parser.parse(episode.get('startTime'))) == mindate),
                                 None)
        else:
            duration = offairdate - onairdate
            midairdate = onairdate + timedelta(
                seconds=duration.total_seconds() / 2)
            mindate = min(
                abs(midairdate -
                    (dateutil.parser.parse(episode.get('startTime')) +
                     timedelta(seconds=(dateutil.parser.parse(
                         episode.get('endTime')) - dateutil.parser.parse(
                             episode.get('startTime'))).total_seconds() / 2)))
                for episode in episodes)
            episode_guess = next((episode for episode in episodes if abs(
                midairdate -
                (dateutil.parser.parse(episode.get('startTime')) + timedelta(
                    seconds=(dateutil.parser.parse(episode.get('endTime')) -
                             dateutil.parser.parse(episode.get('startTime'))
                             ).total_seconds() / 2))) == mindate), None)

        if episode_guess and episode_guess.get('vrt.whatson-id', None):
            offairdate_guess = dateutil.parser.parse(
                episode_guess.get('endTime'))
            video = self.get_single_episode(
                whatson_id=episode_guess.get('vrt.whatson-id'))
            if video:
                return video

            # Airdate live2vod feature: use livestream cache of last 24 hours if no video was found

            if now - timedelta(hours=24) <= dateutil.parser.parse(
                    episode_guess.get('endTime')) <= now:
                start_date = onairdate.astimezone(
                    dateutil.tz.UTC).isoformat()[0:19]
                end_date = offairdate_guess.astimezone(
                    dateutil.tz.UTC).isoformat()[0:19]

            # Offairdate defined
            if offairdate and now - timedelta(hours=24) <= offairdate <= now:
                start_date = onairdate.astimezone(
                    dateutil.tz.UTC).isoformat()[:19]
                end_date = offairdate.astimezone(
                    dateutil.tz.UTC).isoformat()[:19]

            if start_date and end_date:
                info = self._metadata.get_info_labels(episode_guess,
                                                      channel=channel,
                                                      date=start_date)
                live2vod_title = '{} ({})'.format(
                    info.get('tvshowtitle'),
                    localize(30454))  # from livestream cache
                info.update(tvshowtitle=live2vod_title)
                video_item = TitleItem(
                    label=self._metadata.get_label(episode_guess),
                    art_dict=self._metadata.get_art(episode_guess),
                    info_dict=info,
                    prop_dict=self._metadata.get_properties(episode_guess),
                )
                video = dict(
                    listitem=video_item,
                    video_id=channel.get('live_stream_id'),
                    start_date=start_date,
                    end_date=end_date,
                )
                return video

            video = dict(errorlabel=episode_guess.get('title'))
        return video