Ejemplo n.º 1
0
def add_favorite(user_id, username):
    """Add a user to favorites"""
    # Add favorite to dictionary
    favs = Favorites(wf())
    favs.add(user_id, username)
    # Reload user
    load_user(user_id, username)
Ejemplo n.º 2
0
def make_add_or_remove_favorite_item(user_id, username):
    """Create an alfred item to add or remove a user from favorites"""
    # Add item depending on if this user is a favorite
    favs = Favorites(wf())
    favUsers = favs.get_favorites()
    special_unicode_value = wf().alfred_items.special_unicode_value.next()
    command = None
    if favUsers is not None:
        if user_id in favUsers:
            wf().add_item( title=u'Remove from favorites',
                           autocomplete=unichr(special_unicode_value),
                           icon=ICON_TRASH)
            command = REMOVE_FAV
        else:
            wf().add_item(title=u'Add to favorites',
                        autocomplete=unichr(special_unicode_value))
            command = ADD_FAV
    # Else user is not a favorite because the 'favorites' file doesnt exist
    else:
        wf().add_item(title=u'Create a favorite',
                    autocomplete=unichr(special_unicode_value))
        command = ADD_FAV
    # Update special info
    data = {special_unicode_value: (command, {'user_id': user_id, 'username': username})}
    wf().alfred_items.special_info.send(data)
Ejemplo n.º 3
0
	def main_page(self):
		favorites = Favorites()
		theme_manager = ThemeManager()
		return template(
			"project",
			CSS = theme_manager.apply(self.dao.project["theme"]),
			favorites_options = favorites.make_options(),
			theme_options = theme_manager.make_options(),
			is_favorite = favorites.is_favorite(),
			project_name = self.dao.project["name"],
			project = json.dumps(self.dao.project),
			card_background = theme_manager.theme["card_background"]
		)
Ejemplo n.º 4
0
 def browse(self, path):
     favorites = Favorites()
     theme_manager = ThemeManager()
     for root, folders, files in os.walk(path):
         folders.sort()
         return template("browse",
                         CSS=theme_manager.apply("default"),
                         favorites_options=favorites.make_options(),
                         theme_options=theme_manager.make_options(),
                         drives=self.get_drives(),
                         parent=os.path.abspath(
                             os.path.join(path, os.pardir)),
                         folders=folders,
                         path=root,
                         isAProject=("LUCID.json" in files))
    def __init__(self):
        """PlayerInfo initialisation"""
        self.resumepoints = ResumePoints()
        self.apihelper = ApiHelper(Favorites(), self.resumepoints)
        self.last_pos = None
        self.listen = False
        self.paused = False
        self.total = 100
        self.positionthread = None
        self.quit = Event()

        self.asset_str = None
        # FIXME On Kodi 17, use ListItem.Filenameandpath because Player.FilenameAndPath returns the stream manifest url and
        # this definitely breaks "Up Next" on Kodi 17, but this is not supported or available through the Kodi add-on repo anyway
        self.path_infolabel = 'ListItem.Filenameandpath' if kodi_version_major(
        ) < 18 else 'Player.FilenameAndPath'
        self.path = None
        self.title = None
        self.ep_id = None
        self.episode_id = None
        self.episode_title = None
        self.video_id = None
        from random import randint
        self.thread_id = randint(1, 10001)
        log(3, '[PlayerInfo {id}] Initialized', id=self.thread_id)
        super(PlayerInfo, self).__init__()
Ejemplo n.º 6
0
def unfollow(program, title):
    ''' The API interface to unfollow a program used by the context menu '''
    move_down = bool(plugin.args.get('move_down'))
    from favorites import Favorites
    Favorites().unfollow(program=program,
                         title=to_unicode(unquote_plus(from_unicode(title))),
                         move_down=move_down)
Ejemplo n.º 7
0
    def __init__(self, **kwargs):

        super(JournalInterfaceManager, self).__init__(**kwargs)
        self.windows = {}

        # initially load the journal window as main window
        journal_menu = Journal()
        self.add_window("journal_menu", journal_menu)
        self.load_window("journal_menu")

        # add remaining windows to tracked windows
        enter_tasks = AddEntry()
        self.add_window("enter_tasks", enter_tasks)

        update_entry = UpdateEntry()
        self.add_window("update_entry", update_entry)

        review_mistakes = ReviewMistakes()
        self.add_window("review_mistakes", review_mistakes)

        settings = Settings()
        self.add_window("settings", settings)

        collections = Collection()
        self.add_window("collections", collections)

        favourites = Favorites()
        self.add_window("favorites",favourites)
Ejemplo n.º 8
0
def unfollow(program_name, title, program_id=None):
    """The API interface to unfollow a program used by the context menu"""
    move_down = bool(plugin.args.get('move_down'))
    from favorites import Favorites
    Favorites().unfollow(program_name=program_name,
                         title=to_unicode(unquote_plus(from_unicode(title))),
                         program_id=program_id,
                         move_down=move_down)
class TestResumePoints(unittest.TestCase):

    _favorites = Favorites()
    _resumepoints = ResumePoints()
    _apihelper = ApiHelper(_favorites, _resumepoints)

    @unittest.skipUnless(addon.settings.get('username'),
                         'Skipping as VRT username is missing.')
    @unittest.skipUnless(addon.settings.get('password'),
                         'Skipping as VRT password is missing.')
    def test_get_watchlater_episodes(self):
        ''' Test items, sort and order '''
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            page=1, variety='watchlater')
        self.assertTrue(episode_items)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    @unittest.skipUnless(addon.settings.get('username'),
                         'Skipping as VRT username is missing.')
    @unittest.skipUnless(addon.settings.get('password'),
                         'Skipping as VRT password is missing.')
    def test_get_continue_episodes(self):
        ''' Test items, sort and order '''
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            page=1, variety='continue')
        self.assertTrue(episode_items)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    @unittest.skipUnless(addon.settings.get('username'),
                         'Skipping as VRT username is missing.')
    @unittest.skipUnless(addon.settings.get('password'),
                         'Skipping as VRT password is missing.')
    def test_update_watchlist(self):
        self._resumepoints.refresh(ttl=0)
        assetuuid, first_entry = next(
            iter(self._resumepoints._resumepoints.items()))  # pylint: disable=protected-access
        print('%s = %s' % (assetuuid, first_entry))
        url = first_entry.get('value').get('url')
        self._resumepoints.watchlater(uuid=assetuuid, title='Foo bar', url=url)
        self._resumepoints.unwatchlater(uuid=assetuuid,
                                        title='Foo bar',
                                        url=url)
        self._resumepoints.refresh(ttl=0)
        assetuuid, first_entry = next(
            iter(self._resumepoints._resumepoints.items()))  # pylint: disable=protected-access
        print('%s = %s' % (assetuuid, first_entry))

    def test_assetpath_to_uuid(self):
        self.assertEqual(None, self._resumepoints.assetpath_to_uuid(None))

        assetpath = '/content/dam/vrt/2019/08/14/woodstock-depot_WP00157456'
        uuid = 'contentdamvrt20190814woodstockdepotwp00157456'
        self.assertEqual(uuid, self._resumepoints.assetpath_to_uuid(assetpath))
Ejemplo n.º 10
0
    def __init__(self, view_manager_class, model_class):
        self.fav = Favorites(open(Setting.fav_filename))
        self.playlist = Playlist(open(Setting.playlist_filename))

        self.view = view_manager_class(controller=self)
        self.thumb_view = self.view.get_thumb_view()
        self.picture_view = self.view.get_picture_view()
        self.video_view = self.view.get_video_view()

        self.model = model_class(self)
        self.history = History()
        self.loader = Loader()

        self.thumb_loader = self.loader.get_new_thread(
            self.on_thumb_load, self.thumb_view.progress_stop)
        self.picture_loader = self.loader.get_new_thread(
            lambda x: self.picture_view.refresh())

        self.thumb_view.set_cycle_handler(self.cycle_handler)
Ejemplo n.º 11
0
    def init_watching_activity(self):
        ''' Only load components for watching activity when needed '''

        if self._resumepoints.is_activated():
            if not self._playerinfo:
                self._playerinfo = PlayerInfo(info=self.handle_info)
            if not self._favorites:
                self._favorites = Favorites()
            if not self._apihelper:
                self._apihelper = ApiHelper(self._favorites,
                                            self._resumepoints)
Ejemplo n.º 12
0
class TestSearch(unittest.TestCase):

    _favorites = Favorites()
    _resumepoints = ResumePoints()
    _apihelper = ApiHelper(_favorites, _resumepoints)

    def test_search_journaal(self):
        ''' Test for journaal '''
        search_items, sort, ascending, content = self._apihelper.list_search(
            'journaal', page=1)

        # Test we get a non-empty search result
        self.assertEqual(len(search_items), 50)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    def test_search_journaal_page2(self):
        ''' Test for journaal '''
        search_items, sort, ascending, content = self._apihelper.list_search(
            'journaal', page=2)

        # Test we get a non-empty search result
        self.assertEqual(len(search_items), 50)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    def test_search_weer(self):
        ''' Test for journaal '''
        search_items, sort, ascending, content = self._apihelper.list_search(
            'weer', page=1)

        # Test we get a non-empty search result
        self.assertEqual(len(search_items), 50)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    def test_search_unicode(self):
        ''' Test for unicode '''
        search_items, sort, ascending, content = self._apihelper.list_search(
            'René', page=1)

        # Test we get a non-empty search result
        self.assertGreater(len(search_items), 0)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    @staticmethod
    def test_search_empty():
        ''' Test for empty search '''
        Search().search(keywords='')
Ejemplo n.º 13
0
    def init_watching_activity(self):
        """Only load components for watching activity when needed"""

        if self._resumepoints.is_activated():
            if not self._playerinfo:
                self._playerinfo = PlayerInfo()
            if not self._favorites:
                self._favorites = Favorites()
            if not self._apihelper:
                self._apihelper = ApiHelper(self._favorites,
                                            self._resumepoints)
        else:
            self._playerinfo = None
Ejemplo n.º 14
0
def load_favorites():
    """Display favorite users"""   
    max_age_fav = HOUR
    favs = Favorites(wf())
    fav_users = favs.get_favorites()
    if fav_users is not None:
        fav_ids = sorted(fav_users, key=fav_users.get)
        for fav_id in fav_ids:
            fav_username = fav_users[fav_id]
            fav = Grammie(wf(), fav_id, fav_username, command=LOAD_USER, age_info=max_age_fav)
            # Update the cached value of a favorite in case the username changes
            favs.update_info(fav_id, fav.username)          
            fav.display_info()
        # Save favorites to cache
        favs.cache_favs()
    else:
        # No stored favorites, prompt user to add some
        wf().add_item('Add users as favorites to see them here')
Ejemplo n.º 15
0
 def __init__(self):
     """Initialise object"""
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._apihelper = ApiHelper(self._favorites, self._resumepoints)
     wait_for_resumepoints()
Ejemplo n.º 16
0
class TVGuide:
    ''' This implements a VRT TV-guide that offers Kodi menus and TV guide info '''

    VRT_TVGUIDE = 'https://www.vrt.be/bin/epg/schedule.%Y-%m-%d.json'

    def __init__(self):
        ''' Initializes TV-guide object '''
        self._favorites = Favorites()
        self._resumepoints = ResumePoints()
        self._metadata = Metadata(self._favorites, self._resumepoints)
        install_opener(build_opener(ProxyHandler(get_proxies())))

    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)

    @staticmethod
    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(7, -30, -1):
            day = epg + timedelta(days=offset)
            title = 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:
                    title = '[COLOR yellow][B]{name}[/B], {date}[/COLOR]'.format(name=date_name, date=title)
                else:
                    title = '[B]{name}[/B], {date}'.format(name=date_name, date=title)

            # 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.%s.json' % date
            date_items.append(TitleItem(
                title=title,
                path=path,
                art_dict=dict(thumb='DefaultYear.png'),
                info_dict=dict(plot=localize_datelong(day)),
                context_menu=[(localize(30413), 'RunPlugin(%s)' % url_for('delete_cache', cache_file=cache_file))],
            ))
        return date_items

    def get_channel_items(self, date=None, channel=None):
        ''' Offer a menu to select the channel '''
        if date:
            now = datetime.now(dateutil.tz.tzlocal())
            epg = self.parse(date, now)
            datelong = localize_datelong(epg)

        channel_items = []
        for chan in CHANNELS:
            # Only some channels are supported
            if not chan.get('has_tvguide'):
                continue

            # If a channel is requested, stop processing if it is no match
            if channel and channel != chan.get('name'):
                continue

            art_dict = {}

            # Try to use the white icons for thumbnails (used for icons as well)
            if has_addon('resource.images.studios.white'):
                art_dict['thumb'] = 'resource://resource.images.studios.white/{studio}.png'.format(**chan)
            else:
                art_dict['thumb'] = 'DefaultTags.png'

            if date:
                title = chan.get('label')
                path = url_for('tvguide', date=date, channel=chan.get('name'))
                plot = '%s\n%s' % (localize(30302, **chan), datelong)
            else:
                title = '[B]%s[/B]' % localize(30303, **chan)
                path = url_for('tvguide_channel', channel=chan.get('name'))
                plot = '%s\n\n%s' % (localize(30302, **chan), self.live_description(chan.get('name')))

            channel_items.append(TitleItem(
                title=title,
                path=path,
                art_dict=art_dict,
                info_dict=dict(plot=plot, studio=chan.get('studio')),
            ))
        return channel_items

    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=60 * 60)

        cache_file = 'schedule.%s.json' % date
        if date in ('today', 'yesterday', 'tomorrow'):
            # Try the cache if it is fresh
            schedule = get_cache(cache_file, ttl=60 * 60)
            if not schedule:
                from json import load
                log(2, 'URL get: {url}', url=epg_url)
                schedule = load(urlopen(epg_url))
                update_cache(cache_file, schedule)
        else:
            from json import load
            log(2, 'URL get: {url}', url=epg_url)
            schedule = load(urlopen(epg_url))

        entry = find_entry(CHANNELS, 'name', channel)
        if entry:
            episodes = schedule.get(entry.get('id'), [])
        else:
            episodes = []
        episode_items = []
        for episode in episodes:

            label = self._metadata.get_label(episode)

            context_menu = []
            path = None
            if episode.get('url'):
                from statichelper import add_https_method, url_to_program
                video_url = add_https_method(episode.get('url'))
                path = url_for('play_url', video_url=video_url)
                program = url_to_program(episode.get('url'))
                context_menu, favorite_marker, watchlater_marker = self._metadata.get_context_menu(episode, program, cache_file)
                label += favorite_marker + watchlater_marker

            info_labels = self._metadata.get_info_labels(episode, date=date, channel=entry)
            info_labels['title'] = label

            episode_items.append(TitleItem(
                title=label,
                path=path,
                art_dict=self._metadata.get_art(episode),
                info_dict=info_labels,
                is_playable=True,
                context_menu=context_menu,
            ))
        return episode_items

    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)
        # Try the cache if it is fresh
        schedule = get_cache('schedule.today.json', ttl=60 * 60)
        if not schedule:
            from json import load
            epg_url = epg.strftime(self.VRT_TVGUIDE)
            log(2, 'URL get: {url}', url=epg_url)
            schedule = load(urlopen(epg_url))
            update_cache('schedule.today.json', schedule)

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

        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 ''

    @staticmethod
    def episode_description(episode):
        ''' Return a formatted description for an episode '''
        return '{start} - {end}\n» {title}'.format(**episode)

    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)
        # Try the cache if it is fresh
        schedule = get_cache('schedule.today.json', ttl=60 * 60)
        if not schedule:
            from json import load
            epg_url = epg.strftime(self.VRT_TVGUIDE)
            log(2, 'URL get: {url}', url=epg_url)
            schedule = load(urlopen(epg_url))
            update_cache('schedule.today.json', schedule)

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

        episodes = iter(schedule.get(entry.get('id'), []))

        description = ''
        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 yellow][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 not description:
            # Add a final 'No transmission' program
            description = '[COLOR yellow][B]%s[/B] %s - 06:00\n» %s[/COLOR]' % (localize(30421), episode.get('end'), localize(30423))
        return description

    @staticmethod
    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)
Ejemplo n.º 17
0
class VRTPlayer:
    """An object providing all methods for Kodi menu generation"""

    def __init__(self):
        """Initialise object"""
        self._favorites = Favorites()
        self._resumepoints = ResumePoints()
        self._apihelper = ApiHelper(self._favorites, self._resumepoints)
        wait_for_resumepoints()

    def show_main_menu(self):
        """The VRT NU add-on main menu"""
        # self._favorites.refresh(ttl=ttl('indirect'))
        main_items = []

        # Only add 'My favorites' when it has been activated
        if self._favorites.is_activated():
            main_items.append(TitleItem(
                label=localize(30010),  # My favorites
                path=url_for('favorites_menu'),
                art_dict=dict(thumb='DefaultFavourites.png'),
                info_dict=dict(plot=localize(30011)),
            ))

        main_items.extend([
            TitleItem(label=localize(30012),  # All programs
                      path=url_for('programs'),
                      art_dict=dict(thumb='DefaultMovieTitle.png'),
                      info_dict=dict(plot=localize(30013))),
            TitleItem(label=localize(30014),  # Categories
                      path=url_for('categories'),
                      art_dict=dict(thumb='DefaultGenre.png'),
                      info_dict=dict(plot=localize(30015))),
            TitleItem(label=localize(30016),  # Channels
                      path=url_for('channels'),
                      art_dict=dict(thumb='DefaultTags.png'),
                      info_dict=dict(plot=localize(30017))),
            TitleItem(label=localize(30018),  # Live TV
                      path=url_for('livetv'),
                      art_dict=dict(thumb='DefaultTVShows.png'),
                      info_dict=dict(plot=localize(30019))),
            TitleItem(label=localize(30020),  # Recent items
                      path=url_for('recent'),
                      art_dict=dict(thumb='DefaultRecentlyAddedEpisodes.png'),
                      info_dict=dict(plot=localize(30021))),
            TitleItem(label=localize(30022),  # Soon offline
                      path=url_for('offline'),
                      art_dict=dict(thumb='DefaultYear.png'),
                      info_dict=dict(plot=localize(30023))),
            TitleItem(label=localize(30024),  # Featured content
                      path=url_for('featured'),
                      art_dict=dict(thumb='DefaultCountry.png'),
                      info_dict=dict(plot=localize(30025))),
            TitleItem(label=localize(30026),  # TV guide
                      path=url_for('tvguide'),
                      art_dict=dict(thumb='DefaultAddonTvInfo.png'),
                      info_dict=dict(plot=localize(30027))),
            TitleItem(label=localize(30028),  # Search
                      path=url_for('search'),
                      art_dict=dict(thumb='DefaultAddonsSearch.png'),
                      info_dict=dict(plot=localize(30029))),
        ])
        show_listing(main_items, cache=False)  # No category
        self._version_check()

    def _version_check(self):
        first_run, settings_version, addon_version = self._first_run()
        if first_run:
            # 2.0.0 version: changed plugin:// url interface: show warning that Kodi favourites and what-was-watched will break
            if settings_version == '' and has_credentials():
                ok_dialog(localize(30978), localize(30979))

            if addon_version == '2.2.1':
                # 2.2.1 version: changed artwork: delete old cached artwork
                delete_cached_thumbnail(get_addon_info('fanart').replace('.png', '.jpg'))
                delete_cached_thumbnail(get_addon_info('icon'))
                # 2.2.1 version: moved tokens: delete old tokens
                from tokenresolver import TokenResolver
                TokenResolver().delete_tokens()

            # Make user aware that timeshift functionality will not work without ISA when user starts up the first time
            if settings_version == '' and kodi_version_major() > 17 and not has_inputstream_adaptive():
                ok_dialog(message=localize(30988))

    @staticmethod
    def _first_run():
        '''Check if this add-on version is run for the first time'''

        # Get version from settings.xml
        settings_version = get_setting('version', default='')

        # Get version from addon.xml
        addon_version = get_addon_info('version')

        # Compare versions (settings_version was not present in version 1.10.0 and older)
        settings_comp = tuple(map(int, settings_version.split('+')[0].split('.'))) if settings_version != '' else (1, 10, 0)
        addon_comp = tuple(map(int, addon_version.split('+')[0].split('.')))

        if addon_comp > settings_comp:
            # New version found, save addon version to settings
            set_setting('version', addon_version)
            return True, settings_version, addon_version

        return False, settings_version, addon_version

    def show_favorites_menu(self):
        """The VRT NU addon 'My programs' menu"""
        self._favorites.refresh(ttl=ttl('indirect'))
        favorites_items = [
            TitleItem(label=localize(30040),  # My programs
                      path=url_for('favorites_programs'),
                      art_dict=dict(thumb='DefaultMovieTitle.png'),
                      info_dict=dict(plot=localize(30041))),
            TitleItem(label=localize(30048),  # My recent items
                      path=url_for('favorites_recent'),
                      art_dict=dict(thumb='DefaultRecentlyAddedEpisodes.png'),
                      info_dict=dict(plot=localize(30049))),
            TitleItem(label=localize(30050),  # My soon offline
                      path=url_for('favorites_offline'),
                      art_dict=dict(thumb='DefaultYear.png'),
                      info_dict=dict(plot=localize(30051))),
        ]

        # Only add 'My watch later' and 'Continue watching' when it has been activated
        if self._resumepoints.is_activated():
            favorites_items.append(TitleItem(
                label=localize(30052),  # My watch later
                path=url_for('resumepoints_watchlater'),
                art_dict=dict(thumb='DefaultVideoPlaylists.png'),
                info_dict=dict(plot=localize(30053)),
            ))
            favorites_items.append(TitleItem(
                label=localize(30054),  # Continue Watching
                path=url_for('resumepoints_continue'),
                art_dict=dict(thumb='DefaultInProgressShows.png'),
                info_dict=dict(plot=localize(30055)),
            ))

        if get_setting_bool('addmymovies', default=True):
            favorites_items.append(
                TitleItem(label=localize(30042),  # My movies
                          path=url_for('categories', category='films'),
                          art_dict=dict(thumb='DefaultAddonVideo.png'),
                          info_dict=dict(plot=localize(30043))),
            )

        if get_setting_bool('addmydocu', default=True):
            favorites_items.append(
                TitleItem(label=localize(30044),  # My documentaries
                          path=url_for('favorites_docu'),
                          art_dict=dict(thumb='DefaultMovies.png'),
                          info_dict=dict(plot=localize(30045))),
            )

        if get_setting_bool('addmymusic', default=True):
            favorites_items.append(
                TitleItem(label=localize(30046),  # My music
                          path=url_for('favorites_music'),
                          art_dict=dict(thumb='DefaultAddonMusic.png'),
                          info_dict=dict(plot=localize(30047))),
            )

        show_listing(favorites_items, category=30010, cache=False)  # My favorites

        # Show dialog when no favorites were found
        if not self._favorites.titles():
            ok_dialog(heading=localize(30415), message=localize(30416))

    def show_favorites_docu_menu(self):
        """The VRT NU add-on 'My documentaries' listing menu"""
        self._favorites.refresh(ttl=ttl('indirect'))
        self._resumepoints.refresh(ttl=ttl('indirect'))
        episode_items, sort, ascending, content = self._apihelper.list_episodes(category='docu', season='allseasons', programtype='oneoff')
        show_listing(episode_items, category=30044, sort=sort, ascending=ascending, content=content, cache=False)

    def show_favorites_music_menu(self):
        """The VRT NU add-on 'My music' listing menu"""
        self._favorites.refresh(ttl=ttl('indirect'))
        self._resumepoints.refresh(ttl=ttl('indirect'))
        episode_items, sort, ascending, content = self._apihelper.list_episodes(category='muziek', season='allseasons', programtype='oneoff')
        show_listing(episode_items, category=30046, sort=sort, ascending=ascending, content=content, cache=False)

    def show_tvshow_menu(self, use_favorites=False):
        """The VRT NU add-on 'All programs' listing menu"""
        # My favorites menus may need more up-to-date favorites
        self._favorites.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        self._resumepoints.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        tvshow_items = self._apihelper.list_tvshows(use_favorites=use_favorites)
        show_listing(tvshow_items, category=30440, sort='label', content='tvshows')  # A-Z

    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 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 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_livetv_menu(self):
        """The VRT NU add-on 'Live TV' listing menu"""
        channel_items = self._apihelper.list_channels()
        show_listing(channel_items, category=30018, cache=False)

    def show_episodes_menu(self, program, season=None):
        """The VRT NU add-on episodes listing menu"""
        self._favorites.refresh(ttl=ttl('indirect'))
        self._resumepoints.refresh(ttl=ttl('indirect'))
        episode_items, sort, ascending, content = self._apihelper.list_episodes(program=program, season=season)
        # FIXME: Translate program in Program Title
        show_listing(episode_items, category=program.title(), sort=sort, ascending=ascending, content=content, cache=False)

    def show_recent_menu(self, page=0, use_favorites=False):
        """The VRT NU add-on 'Most recent' and 'My most recent' listing menu"""

        # My favorites menus may need more up-to-date favorites
        self._favorites.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        self._resumepoints.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        page = realpage(page)
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=page, use_favorites=use_favorites, variety='recent')

        # Add 'More...' entry at the end
        if len(episode_items) == get_setting_int('itemsperpage', default=50):
            recent = 'favorites_recent' if use_favorites else 'recent'
            episode_items.append(TitleItem(
                label=colour(localize(30300)),
                path=url_for(recent, page=page + 1),
                art_dict=dict(thumb='DefaultRecentlyAddedEpisodes.png'),
                info_dict=dict(),
            ))

        show_listing(episode_items, category=30020, sort=sort, ascending=ascending, content=content, cache=False)

    def show_offline_menu(self, page=0, use_favorites=False):
        """The VRT NU add-on 'Soon offline' and 'My soon offline' listing menu"""

        # My favorites menus may need more up-to-date favorites
        self._favorites.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        self._resumepoints.refresh(ttl=ttl('direct' if use_favorites else 'indirect'))
        page = realpage(page)
        items_per_page = get_setting_int('itemsperpage', default=50)
        sort_key = 'assetOffTime'
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=page, items_per_page=items_per_page, use_favorites=use_favorites,
                                                                                variety='offline', sort_key=sort_key)

        # Add 'More...' entry at the end
        if len(episode_items) == items_per_page:
            offline = 'favorites_offline' if use_favorites else 'offline'
            episode_items.append(TitleItem(
                label=localize(30300),
                path=url_for(offline, page=page + 1),
                art_dict=dict(thumb='DefaultYear.png'),
                info_dict=dict(),
            ))

        show_listing(episode_items, category=30022, sort=sort, ascending=ascending, content=content, cache=False)

    def show_watchlater_menu(self, page=0):
        """The VRT NU add-on 'My watch later' listing menu"""

        # My watch later menu may need more up-to-date favorites
        self._favorites.refresh(ttl=ttl('direct'))
        self._resumepoints.refresh(ttl=ttl('direct'))
        page = realpage(page)
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=page, variety='watchlater')
        show_listing(episode_items, category=30052, sort=sort, ascending=ascending, content=content, cache=False)

    def show_continue_menu(self, page=0):
        """The VRT NU add-on 'Continue waching' listing menu"""

        # Continue watching menu may need more up-to-date favorites
        self._favorites.refresh(ttl=ttl('direct'))
        self._resumepoints.refresh(ttl=ttl('direct'))
        page = realpage(page)
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=page, variety='continue')
        show_listing(episode_items, category=30054, sort=sort, ascending=ascending, content=content, cache=False)

    def play_latest_episode(self, program):
        """A hidden feature in the VRT NU add-on to play the latest episode of a program"""
        video = self._apihelper.get_latest_episode(program)
        if not video:
            log_error('Play latest episode failed, program {program}', program=program)
            ok_dialog(message=localize(30954))
            end_of_directory()
            return
        self.play(video)

    def play_episode_by_air_date(self, channel, start_date, end_date):
        """Play an episode of a program given the channel and the air date in iso format (2019-07-06T19:35:00)"""
        video = self._apihelper.get_episode_by_air_date(channel, start_date, end_date)
        if video and video.get('errorlabel'):
            ok_dialog(message=localize(30986, title=video.get('errorlabel')))
            end_of_directory()
            return
        if not video:
            log_error('Play episode by air date failed, channel {channel}, start_date {start}', channel=channel, start=start_date)
            ok_dialog(message=localize(30954))
            end_of_directory()
            return
        self.play(video)

    def play_episode_by_whatson_id(self, whatson_id):
        """Play an episode of a program given the whatson_id"""
        video = self._apihelper.get_single_episode(whatson_id=whatson_id)
        if not video:
            log_error('Play episode by whatson_id failed, whatson_id {whatson_id}', whatson_id=whatson_id)
            ok_dialog(message=localize(30954))
            end_of_directory()
            return
        self.play(video)

    def play_upnext(self, video_id):
        """Play the next episode of a program by video_id"""
        video = self._apihelper.get_single_episode(video_id=video_id)
        if not video:
            log_error('Play Up Next with video_id {video_id} failed', video_id=video_id)
            ok_dialog(message=localize(30954))
            end_of_directory()
            return
        self.play(video)

    @staticmethod
    def play(video):
        """A wrapper for playing video items"""
        from tokenresolver import TokenResolver
        from streamservice import StreamService
        _tokenresolver = TokenResolver()
        _streamservice = StreamService(_tokenresolver)
        stream = _streamservice.get_stream(video)
        if stream is None:
            end_of_directory()
            return
        play(stream, video.get('listitem'))
Ejemplo n.º 18
0
def favorites_manage():
    ''' The API interface to manage your favorites '''
    from favorites import Favorites
    Favorites().manage()
Ejemplo n.º 19
0
def follow(program, title):
    ''' The API interface to follow a program used by the context menu '''
    from favorites import Favorites
    Favorites().follow(program=program,
                       title=to_unicode(unquote_plus(from_unicode(title))))
Ejemplo n.º 20
0
'''
Favorite Files
Licensed under MIT
Copyright (c) 2012 Isaac Muse <*****@*****.**>
'''

import sublime
import sublime_plugin
from os.path import join, exists, normpath
from favorites import Favorites

Favs = Favorites(
    join(sublime.packages_path(), 'User', 'favorite_files_list.json'))


class Refresh:
    dummy_file = normpath(
        join(sublime.packages_path(), 'FavoriteFiles', 'refresh.txt'))
    on = False


class CleanOrphanedFavoritesCommand(sublime_plugin.WindowCommand):
    def run(self):
        # Clean out all dead links
        if not Favs.load(clean=True, win_id=self.window.id()):
            Favs.load(force=True, clean=True, win_id=self.window.id())


class SelectFavoriteFileCommand(sublime_plugin.WindowCommand):
    def open_file(self, value, group=False):
        if value >= 0:
Ejemplo n.º 21
0
 def __init__(self):
     ''' Initialize searchtes, relies on XBMC vfs '''
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._search_history = get_userdata_path() + 'search_history.json'
Ejemplo n.º 22
0
 def __init__(self):
     ''' Initializes TV-guide object '''
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._metadata = Metadata(self._favorites, self._resumepoints)
     install_opener(build_opener(ProxyHandler(get_proxies())))
Ejemplo n.º 23
0
class Search:
    """Search and cache search queries"""

    def __init__(self):
        """Initialize searchtes, relies on XBMC vfs"""
        self._favorites = Favorites()
        self._resumepoints = ResumePoints()
        self._search_history = addon_profile() + 'search_history.json'

    def read_history(self):
        """Read search history from disk"""
        with open_file(self._search_history, 'r') as fdesc:
            return get_json_data(fdesc, fail=[])

    def write_history(self, history):
        """Write search history to disk"""
        from json import dump
        with open_file(self._search_history, 'w') as fdesc:
            dump(history, fdesc)

    def search_menu(self):
        """Main search menu"""
        from helperobjects import TitleItem
        menu_items = [
            TitleItem(
                label=localize(30424),  # New search...
                path=url_for('search_query'),
                art_dict=dict(thumb='DefaultAddonsSearch.png'),
                info_dict=dict(plot=localize(30425)),
                is_playable=False,
            )
        ]

        history = self.read_history()
        for keywords in history:
            menu_items.append(TitleItem(
                label=keywords,
                path=url_for('search_query', keywords=keywords),
                is_playable=False,
                context_menu=[(
                    localize(30033),  # Edit
                    'RunPlugin(%s)' % url_for('edit_search', keywords=keywords),
                ), (
                    localize(30030),  # Remove
                    'RunPlugin(%s)' % url_for('remove_search', keywords=keywords),
                )],
            ))

        if history:
            menu_items.append(TitleItem(
                label=localize(30426),  # Clear search history
                path=url_for('clear_search'),
                info_dict=dict(plot=localize(30427)),
                art_dict=dict(thumb='icons/infodialogs/uninstall.png'),
                is_playable=False,
            ))

        show_listing(menu_items, category=30031, cache=False)

    def search(self, keywords=None, page=0, edit=False):
        """The VRT NU add-on Search functionality and results"""
        if keywords is None or edit is True:
            keywords = get_search_string(keywords)

        if not keywords:
            end_of_directory()
            return
        if edit is True:
            container_update(url_for('search_query', keywords=keywords))
            return

        from apihelper import ApiHelper
        from utils import realpage
        page = realpage(page)

        self.add(keywords)

        search_items, sort, ascending, content = ApiHelper(self._favorites, self._resumepoints).list_search(keywords, page=page)
        if not search_items:
            ok_dialog(heading=localize(30135), message=localize(30136, keywords=keywords))
            end_of_directory()
            return

        # Add 'More…' entry at the end
        from helperobjects import TitleItem
        if len(search_items) == get_setting_int('itemsperpage', default=50):
            search_items.append(TitleItem(
                label=colour(localize(30300)),  # More…
                path=url_for('search_query', keywords=keywords, page=page + 1),
                art_dict=dict(thumb='DefaultAddonSearch.png'),
                info_dict={},
            ))

        self._favorites.refresh(ttl=ttl('indirect'))
        show_listing(search_items, category=30032, sort=sort, ascending=ascending, content=content, cache=False)

    def clear(self):
        """Clear the search history"""
        self.write_history([])
        end_of_directory()

    def add(self, keywords):
        """Add new keywords to search history"""
        history = self.read_history()

        # Remove if keywords already was listed
        try:
            history.remove(keywords)
        except ValueError:
            pass

        history.insert(0, keywords)

        self.write_history(history)

    def remove(self, keywords):
        """Remove existing keywords from search history"""
        history = self.read_history()

        try:
            history.remove(keywords)
        except ValueError:
            return

        # If keywords was successfully removed, write to disk
        self.write_history(history)

        input_down()
        container_refresh()
class TestFavorites(unittest.TestCase):

    _favorites = Favorites()
    _resumepoints = ResumePoints()
    _apihelper = ApiHelper(_favorites, _resumepoints)

    def test_get_recent_episodes(self):
        ''' Test items, sort and order '''
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=1, variety='recent')
        self.assertEqual(len(episode_items), 50)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    def test_get_offline_episodes(self):
        ''' Test items, sort and order '''
        episode_items, sort, ascending, content = self._apihelper.list_episodes(page=1, variety='offline')
        self.assertTrue(episode_items)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

    @unittest.SkipTest
    def test_unfollow_all(self):
        programs = self._apihelper.get_tvshows()
        for program_item in programs:
            program_title = program_item.get('title')
            program = program_item.get('programName')
            if self._favorites.is_favorite(program):
                # Unfollow
                self._favorites.unfollow(program=program, title=program_title)
                self.assertFalse(self._favorites.is_favorite(program))

    @unittest.SkipTest
    def test_follow_number(self):
        number = 118
        programs = self._apihelper.get_tvshows()
        shuffle(programs)
        print('VRT NU has %d programs available' % len(programs))
        for program_item in programs[:number]:
            program_title = program_item.get('title')
            program = program_item.get('programName')

            # Follow
            self._favorites.follow(program=program, title=program_title)
            self.assertTrue(self._favorites.is_favorite(program))

            # Unfollow
            # self._favorites.unfollow(program=program, title=program_title)
            # self.assertFalse(self._favorites.is_favorite(program))

    @unittest.skipUnless(addon.settings.get('username'), 'Skipping as VRT username is missing.')
    @unittest.skipUnless(addon.settings.get('password'), 'Skipping as VRT password is missing.')
    def test_follow_unfollow(self):
        programs = [
            {'program_title': 'Winteruur', 'program': 'winteruur'},
            {'program_title': 'De Campus Cup', 'program': 'de-campus-cup'},
            {'program_title': 'Terug naar Siberië', 'program': 'terug-naar-siberie'},
            {'program_title': 'Belle & Sebastian', 'program': 'belle---sebastian'},
        ]
        for program_item in programs:
            program_title = program_item.get('program_title')
            program = program_item.get('program')
            self._favorites.follow(program=program, title=program_title)
            self.assertTrue(self._favorites.is_favorite(program))

            self._favorites.unfollow(program=program, title=program_title)
            self.assertFalse(self._favorites.is_favorite(program))

            self._favorites.follow(program=program, title=program_title)
            self.assertTrue(self._favorites.is_favorite(program))

    def test_programs(self):
        programs = self._favorites.programs()
        # NOTE: Getting favorites requires credentials
        if addon.settings.get('username') and addon.settings.get('password'):
            self.assertTrue(programs)
        print(programs)

    def test_titles(self):
        titles = self._favorites.titles()
        # NOTE: Getting favorites requires credentials
        if addon.settings.get('username') and addon.settings.get('password'):
            self.assertTrue(titles)
        print(sorted(titles))
Ejemplo n.º 25
0
 def __init__(self):
     ''' Initialise object '''
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._apihelper = ApiHelper(self._favorites, self._resumepoints)
Ejemplo n.º 26
0
def follow(program_name, title, program_id=None):
    """The API interface to follow a program used by the context menu"""
    from favorites import Favorites
    Favorites().follow(program_name=program_name,
                       title=to_unicode(unquote_plus(from_unicode(title))),
                       program_id=program_id)
Ejemplo n.º 27
0
class TVGuide:
    """This implements a VRT TV-guide that offers Kodi menus and TV guide info"""

    VRT_TVGUIDE = 'https://www.vrt.be/bin/epg/schedule.%Y-%m-%d.json'

    def __init__(self):
        """Initializes TV-guide object"""
        self._favorites = Favorites()
        self._resumepoints = ResumePoints()
        self._metadata = Metadata(self._favorites, self._resumepoints)

    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)

    @staticmethod
    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 get_channel_items(self, date=None, channel=None):
        """Offer a menu to select the channel"""
        if date:
            now = datetime.now(dateutil.tz.tzlocal())
            epg = self.parse(date, now)
            datelong = localize_datelong(epg)

        channel_items = []
        for chan in CHANNELS:
            # Only some channels are supported
            if not chan.get('has_tvguide'):
                continue

            # If a channel is requested, stop processing if it is no match
            if channel and channel != chan.get('name'):
                continue

            art_dict = {}

            # Try to use the white icons for thumbnails (used for icons as well)
            if has_addon('resource.images.studios.white'):
                art_dict[
                    'thumb'] = 'resource://resource.images.studios.white/{studio}.png'.format(
                        **chan)
            else:
                art_dict['thumb'] = 'DefaultTags.png'

            if date:
                label = chan.get('label')
                path = url_for('tvguide', date=date, channel=chan.get('name'))
                plot = '[B]%s[/B]\n%s' % (datelong, localize(30302, **chan))
            else:
                label = '[B]%s[/B]' % localize(30303, **chan)
                path = url_for('tvguide_channel', channel=chan.get('name'))
                plot = '%s\n\n%s' % (localize(
                    30302, **chan), self.live_description(chan.get('name')))

            context_menu = [(
                localize(30413),  # Refresh menu
                'RunPlugin(%s)' %
                url_for('delete_cache',
                        cache_file='channel.{channel}.json'.format(
                            channel=chan.get('name'))),
            )]

            channel_items.append(
                TitleItem(
                    label=label,
                    path=path,
                    art_dict=art_dict,
                    context_menu=context_menu,
                    info_dict=dict(plot=plot, studio=chan.get('studio')),
                ))
        return channel_items

    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

    @staticmethod
    def get_episode_path(episode, channel):
        """Return a playable plugin:// path for an episode"""
        now = datetime.now(dateutil.tz.tzlocal())
        end_date = dateutil.parser.parse(episode.get('endTime'))
        if episode.get('url') and episode.get('vrt.whatson-id'):
            return url_for('play_whatson_id',
                           whatson_id=episode.get('vrt.whatson-id'))
        if now - timedelta(hours=24) <= end_date <= now:
            return url_for('play_air_date', channel,
                           episode.get('startTime')[:19],
                           episode.get('endTime')[:19])
        return url_for('noop', whatsonid=episode.get('vrt.whatson-id', ''))

    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 ''

    @staticmethod
    def episode_description(episode):
        """Return a formatted description for an episode"""
        return '{start} - {end}\n» {title}'.format(**episode)

    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)

    @staticmethod
    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)
Ejemplo n.º 28
0
 def __init__(self):
     """Initializes TV-guide object"""
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._metadata = Metadata(self._favorites, self._resumepoints)
Ejemplo n.º 29
0
class TestVRTPlayer(unittest.TestCase):

    _favorites = Favorites()
    _resumepoints = ResumePoints()
    _apihelper = ApiHelper(_favorites, _resumepoints)
    _vrtplayer = VRTPlayer()

    def test_show_videos_single_episode_shows_videos(self):
        program = 'marathonradio'
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            program=program)
        self.assertTrue(episode_items, msg=program)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

        self._vrtplayer.show_episodes_menu(program)

    def test_show_videos_single_season_shows_videos(self):
        program = 'het-weer'
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            program=program)
        self.assertTrue(episode_items, msg=program)
        self.assertEqual(sort, 'dateadded')
        self.assertFalse(ascending)
        self.assertEqual(content, 'episodes')

        self._vrtplayer.show_episodes_menu(program)

    def test_show_videos_multiple_seasons_shows_videos(self):
        program = 'pano'
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            program=program)
        self.assertTrue(episode_items)
        self.assertEqual(sort, 'label')
        self.assertFalse(ascending)
        self.assertEqual(content, 'seasons')

        self._vrtplayer.show_episodes_menu(program)

    def test_show_videos_specific_seasons_shows_videos(self):
        program = 'thuis'
        episode_items, sort, ascending, content = self._apihelper.list_episodes(
            program=program)
        self.assertTrue(episode_items, msg=program)
        self.assertEqual(sort, 'label')
        self.assertFalse(ascending)
        self.assertEqual(content, 'seasons')

        self._vrtplayer.show_episodes_menu(program)

    def test_categories_scraping(self):
        ''' Test to ensure our hardcoded categories conforms to scraped categories '''
        # Remove thumbnails from scraped categories first
        categories_scraped = [
            dict(id=c['id'], name=c['name'])
            for c in self._apihelper.get_categories()
        ]
        categories_stored = [
            dict(id=c['id'], name=c['name']) for c in CATEGORIES
        ]
        self.assertEqual(categories_scraped, categories_stored)

    def test_random_tvshow_episodes(self):
        ''' Rest episode from a random tvshow in a random category '''
        categories = self._apihelper.get_categories()
        self.assertTrue(categories)

        category = random.choice(categories)
        tvshow_items = self._apihelper.list_tvshows(category['id'])
        self.assertTrue(tvshow_items, msg=category['id'])

        tvshow = random.choice(tvshow_items)
        if tvshow.path.startswith('plugin://plugin.video.vrt.nu/programs/'):
            # When random program has episodes
            episode_items, sort, ascending, content = self._apihelper.list_episodes(
                tvshow.path.split('/')[4].replace('.relevant', ''))
            self.assertTrue(episode_items, msg=tvshow.path.split('/')[4])
            self.assertTrue(
                sort in ['dateadded', 'episode', 'label', 'unsorted'])
            self.assertTrue(ascending is True or ascending is False)
            self.assertTrue(
                content in ['episodes', 'seasons'],
                "Content for '%s' is '%s'" % (tvshow.title, content))
        elif tvshow.path.startswith('plugin://plugin.video.vrt.nu/play/id/'):
            # When random program is playable item
            pass
        else:
            self.fail(
                'We did not expect this, either we find episodes or it is a playable item'
            )

    def test_categories(self):
        ''' Test to ensure our hardcoded categories conforms to scraped categories '''
        category_items = self._apihelper.list_categories()
        self.assertEqual(len(category_items), 17)

    def test_featured(self):
        ''' Test to ensure our hardcoded categories conforms to scraped categories '''
        featured_items = self._apihelper.list_featured()
        self.assertEqual(len(featured_items), 9)

    def test_play_unknown_program(self):
        ''' Test playing latest episode of an unknown program '''
        self._vrtplayer.play_latest_episode(program='foobar')

    def test_play_unknown_airdate(self):
        ''' Test playing unknown airdate '''
        self._vrtplayer.play_episode_by_air_date(
            channel='een',
            start_date='2100-01-01T23:59:58',
            end_date='2100-01-01T23:59:59')
        self._vrtplayer.play_episode_by_air_date(
            channel='foo',
            start_date='2100-01-01T23:59:58',
            end_date='2100-01-01T23:59:59')

    def test_play_unknown_whatson_id(self):
        ''' Test playing unknown whatson id '''
        self._vrtplayer.play_whatson(whatson_id='1234567890')
Ejemplo n.º 30
0
 def __init__(self):
     """Initialize searchtes, relies on XBMC vfs"""
     self._favorites = Favorites()
     self._resumepoints = ResumePoints()
     self._search_history = addon_profile() + 'search_history.json'
Ejemplo n.º 31
0
def remove_favorite(user_id, username):
    """Remove a user from favorites"""   
    # Remove favorite from dictionary
    favs = Favorites(wf())
    favs.remove(user_id)
Ejemplo n.º 32
0
def favorites_refresh():
    ''' The API interface to refresh the favorites cache '''
    from favorites import Favorites
    Favorites().refresh(ttl=0)
    notification(message=localize(30982))
Ejemplo n.º 33
0
def favorites_manage():
    """The API interface to manage your favorites"""
    from favorites import Favorites
    Favorites().manage()
Ejemplo n.º 34
0
class Search:
    ''' Search and cache search queries '''
    def __init__(self):
        ''' Initialize searchtes, relies on XBMC vfs '''
        self._favorites = Favorites()
        self._resumepoints = ResumePoints()
        self._search_history = get_userdata_path() + 'search_history.json'

    def read_history(self):
        ''' Read search history from disk '''
        from json import load
        try:
            with open_file(self._search_history, 'r') as fdesc:
                history = load(fdesc)
        except (TypeError, ValueError):  # No JSON object could be decoded
            history = []
        return history

    def write_history(self, history):
        ''' Write search history to disk '''
        from json import dump
        with open_file(self._search_history, 'w') as fdesc:
            dump(history, fdesc)

    def search_menu(self):
        ''' Main search menu '''
        from helperobjects import TitleItem
        menu_items = [
            TitleItem(
                title=localize(30424),  # New search...
                path=url_for('search_query'),
                art_dict=dict(thumb='DefaultAddonsSearch.png'),
                info_dict=dict(plot=localize(30425)),
                is_playable=False,
            )
        ]

        history = self.read_history()
        for keywords in history:
            menu_items.append(
                TitleItem(title=keywords,
                          path=url_for('search_query', keywords=keywords),
                          art_dict=dict(thumb='DefaultAddonsSearch.png'),
                          is_playable=False,
                          context_menu=[
                              (localize(30030), 'RunPlugin(%s)' %
                               url_for('remove_search', keywords=keywords))
                          ]))

        if history:
            menu_items.append(
                TitleItem(
                    title=localize(30426),  # Clear search history
                    path=url_for('clear_search'),
                    info_dict=dict(plot=localize(30427)),
                    art_dict=dict(thumb='icons/infodialogs/uninstall.png'),
                    is_playable=False,
                ))

        show_listing(menu_items, category=30031, cache=False)

    def search(self, keywords=None, page=None):
        ''' The VRT NU add-on Search functionality and results '''
        if keywords is None:
            keywords = get_search_string()

        if not keywords:
            end_of_directory()
            return

        from statichelper import realpage
        page = realpage(page)

        self.add(keywords)

        from apihelper import ApiHelper
        search_items, sort, ascending, content = ApiHelper(
            self._favorites, self._resumepoints).list_search(keywords,
                                                             page=page)
        if not search_items:
            ok_dialog(heading=localize(30135),
                      message=localize(30136, keywords=keywords))
            end_of_directory()
            return

        # Add 'More...' entry at the end
        from helperobjects import TitleItem
        if len(search_items) == 50:
            search_items.append(
                TitleItem(
                    title=localize(30300),
                    path=url_for('search_query',
                                 keywords=keywords,
                                 page=page + 1),
                    art_dict=dict(thumb='DefaultAddonSearch.png'),
                    info_dict=dict(),
                ))

        self._favorites.refresh(ttl=60 * 60)
        show_listing(search_items,
                     category=30032,
                     sort=sort,
                     ascending=ascending,
                     content=content,
                     cache=False)

    def clear(self):
        ''' Clear the search history '''
        self.write_history([])
        end_of_directory()

    def add(self, keywords):
        ''' Add new keywords to search history '''
        history = self.read_history()

        # Remove if keywords already was listed
        try:
            history.remove(keywords)
        except ValueError:
            pass

        history.insert(0, keywords)

        self.write_history(history)

    def remove(self, keywords):
        ''' Remove existing keywords from search history '''
        history = self.read_history()

        try:
            history.remove(keywords)
        except ValueError:
            return

        # If keywords was successfully removed, write to disk
        self.write_history(history)

        container_refresh()