예제 #1
0
    def onNotification(self, sender, method, data):  # pylint: disable=invalid-name
        ''' Handler for notifications '''
        log(2,
            '[Notification] sender={sender}, method={method}, data={data}',
            sender=sender,
            method=method,
            data=to_unicode(data))
        if method.endswith('source_container'):
            from json import loads
            self._container = loads(data).get('container')
            return

        if not sender.startswith('upnextprovider'):
            return
        if not method.endswith('plugin.video.vrt.nu_play_action'):
            return

        from json import loads
        hexdata = loads(data)

        if not hexdata:
            return

        from binascii import unhexlify
        data = loads(unhexlify(hexdata[0]))
        log(2,
            '[Up Next notification] sender={sender}, method={method}, data={data}',
            sender=sender,
            method=method,
            data=to_unicode(data))
        jsonrpc(method='Player.Open',
                params=dict(item=dict(
                    file='plugin://plugin.video.vrt.nu/play/whatson/%s' %
                    data.get('whatson_id'))))
예제 #2
0
    def onNotification(self, sender, method, data=None):  # pylint: disable=invalid-name
        """Handler for Kodi events and data transfer from addons"""

        if not self.state or self.state.is_disabled():
            return

        sender = statichelper.to_unicode(sender)
        method = statichelper.to_unicode(method)
        data = statichelper.to_unicode(data) if data else ''
        self.log(' - '.join([sender, method, data]))

        handler = UpNextMonitor.EVENTS_MAP.get(method)
        if handler:
            handler(self, sender=sender, data=data)
예제 #3
0
def get_setting(setting_id, default=None):
    ''' Get an add-on setting '''
    from xbmcaddon import Addon
    value = to_unicode(Addon().getSetting(setting_id))
    if value == '' and default is not None:
        return default
    return value
예제 #4
0
def get_userdata_path():
    ''' Cache and return the profile's userdata path '''
    if not hasattr(get_userdata_path, 'cached'):
        from xbmcaddon import Addon
        get_userdata_path.cached = to_unicode(
            xbmc.translatePath(Addon().getAddonInfo('profile')))
    return get_userdata_path.cached
예제 #5
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)
예제 #6
0
def unwatchlater(uuid, title, url):
    ''' The API interface to unwatch an episode used by the context menu '''
    from resumepoints import ResumePoints
    ResumePoints().unwatchlater(uuid=uuid,
                                title=to_unicode(
                                    unquote_plus(from_unicode(title))),
                                url=url)
예제 #7
0
def log(msg, name=__name__, level=LOGINFO):
    """Log information to the Kodi log"""

    # Log everything
    if LOG_ENABLE_SETTING == constants.LOG_ENABLE_DEBUG:
        log_enable = level != LOGNONE
    # Only log important messages
    elif LOG_ENABLE_SETTING == constants.LOG_ENABLE_INFO:
        log_enable = LOGDEBUG < level < LOGNONE
    # Log nothing
    else:
        log_enable = False

    if not log_enable:
        return

    # Force minimum required log level to display in Kodi event log
    if level < MIN_LOG_LEVEL:  # pylint: disable=consider-using-max-builtin
        level = MIN_LOG_LEVEL

    # Convert to unicode for string formatting with Unicode literal
    msg = statichelper.to_unicode(msg)
    msg = '[{0}] {1} -> {2}'.format(get_addon_id(), name, msg)
    # Convert back for older Kodi versions
    xbmc.log(statichelper.from_unicode(msg), level=level)
예제 #8
0
def get_search_string():
    ''' Ask the user for a search string '''
    search_string = None
    keyboard = xbmc.Keyboard('', localize(30134))
    keyboard.doModal()
    if keyboard.isConfirmed():
        search_string = to_unicode(keyboard.getText())
    return search_string
예제 #9
0
def get_setting(key, default=None):
    """Get an add-on setting as string"""
    # We use Addon() here to ensure changes in settings are reflected instantly
    try:
        value = to_unicode(Addon().getSetting(key))
    except RuntimeError:  # Occurs when the add-on is disabled
        return default
    if value == '' and default is not None:
        return default
    return value
예제 #10
0
 def getPlayingFile(self):  # pylint: disable=invalid-name
     # Use current stored value if playing forced
     if self.state.forced('playing') or self.state.forced('playing_file'):
         actual = self.state.playing_file
     # Use inbuilt method to store actual value if playing not forced
     else:
         actual = getattr(xbmc.Player, 'getPlayingFile')(self)
     actual = statichelper.to_unicode(actual)
     self.state.playing_file = actual
     # Return actual value or forced value if forced
     return self.state.playing_file
예제 #11
0
 def push_upnext(self, info):
     ''' Push episode info to Up Next service add-on'''
     if has_addon('service.upnext') and get_setting('useupnext',
                                                    'true') == 'true':
         next_info = self._apihelper.get_upnext(info)
         if next_info:
             from binascii import hexlify
             from json import dumps
             data = [to_unicode(hexlify(dumps(next_info).encode()))]
             sender = '%s.SIGNAL' % addon_id()
             notify(sender=sender, message='upnext_data', data=data)
예제 #12
0
 def get_media_type(self):
     # Use current stored value if playing forced
     if self.state.forced('playing') or self.state.forced('media_type'):
         actual = self.state.media_type
     # Use inbuilt method to store actual value if playing not forced
     else:
         actual = self.getVideoInfoTag().getMediaType()
         actual = actual if actual else 'unknowntype'
     actual = statichelper.to_unicode(actual)
     self.state.media_type = actual
     # Return actual value or forced value if forced
     return self.state.media_type
예제 #13
0
def decode_data(encoded):
    """Decode data coming from a notification event"""
    encoding = 'base64'
    from binascii import Error, unhexlify
    try:
        json_data = unhexlify(encoded)
    except (TypeError, Error):
        from base64 import b64decode
        json_data = b64decode(encoded)
    else:
        encoding = 'hex'
    # NOTE: With Python 3.5 and older json.loads() does not support bytes or bytearray, so we convert to unicode
    return json.loads(to_unicode(json_data)), encoding
예제 #14
0
def log(msg, level=0):
    ''' A reimplementation of the xbmc log() function '''
    color1 = '\033[32;1m'
    color2 = '\033[32;0m'
    name = LOGLEVELS[level]
    if level in (4, 5, 6, 7):
        color1 = '\033[31;1m'
        if level in (6, 7):
            raise Exception(msg)
    elif level in (2, 3):
        color1 = '\033[33;1m'
    elif level == 0:
        color2 = '\033[30;1m'
    print('{color1}{name}: {color2}{msg}\033[39;0m'.format(
        name=name, color1=color1, color2=color2, msg=to_unicode(msg)))
예제 #15
0
def get_setting(key, default='', echo=True):
    """Get an addon setting as string"""

    value = default
    # We use Addon() here to ensure changes in settings are reflected instantly
    try:
        value = xbmcaddon.Addon(constants.ADDON_ID).getSetting(key)
        value = statichelper.to_unicode(value)
    # Occurs when the addon is disabled
    except RuntimeError:
        value = default

    if echo:
        log('{0}: {1}'.format(key, value), 'Settings', level=LOGDEBUG)
    return value
예제 #16
0
 def onAVStarted(self):  # pylint: disable=invalid-name
     ''' called when Kodi has a video or audiostream '''
     log(2, '[PlayerInfo] %d onAVStarted' % self._id)
     self._stop.clear()
     self._last_pos = 0
     self._total = self.getTotalTime()
     self._path = getInfoLabel('Player.Filenameandpath')
     tag = self.getVideoInfoTag()
     self._info(dict(
         program=to_unicode(tag.getTVShowTitle()),
         playcount=tag.getPlayCount(),
         rating=tag.getRating(),
         path=self._path,
         runtime=self._total,
     ))
     Thread(target=self.stream_position, name='StreamPosition').start()
예제 #17
0
def decode_data(encoded_data, compat_mode=True):
    """Decode JSON data coming from a notification event"""

    decoded_json = None
    decoded_data = None
    encoding = None

    # Compatibility with Addon Signals which wraps serialised data in square
    # brackets to generate an array/list
    if compat_mode:
        try:
            encoded_data = json.loads(encoded_data)[0]
        except (IndexError, TypeError, ValueError):
            encoded_data = None

    if encoded_data:
        decode_methods = {
            'hex': binascii.unhexlify,
            'base64': base64.b64decode
        }

        for encoding, decode_method in decode_methods.items():
            try:
                decoded_json = decode_method(encoded_data)
                break
            except (TypeError, binascii.Error):
                pass
        else:
            encoding = None

    if decoded_json:
        try:
            # NOTE: With Python 3.5 and older json.loads() does not support
            # bytes or bytearray, so we convert to unicode
            decoded_json = statichelper.to_unicode(decoded_json)
            decoded_data = json.loads(decoded_json)
        except (TypeError, ValueError):
            pass

    return decoded_data, encoding
예제 #18
0
    def get_properties(self, api_data):
        ''' Get properties from single item json api data '''
        properties = dict()

        # Only fill in properties when using VRT NU resumepoints because setting resumetime/totaltime breaks standard Kodi watched status
        if self._resumepoints.is_activated():
            assetpath = self.get_assetpath(api_data)
            if assetpath:
                # We need to ensure forward slashes are quoted
                program_title = statichelper.to_unicode(
                    quote_plus(
                        statichelper.from_unicode(api_data.get('program'))))

                assetuuid = self._resumepoints.assetpath_to_uuid(assetpath)
                url = statichelper.reformat_url(api_data.get('url', ''),
                                                'medium')
                properties.update(assetuuid=assetuuid,
                                  url=url,
                                  title=program_title)

                position = self._resumepoints.get_position(assetuuid)
                total = self._resumepoints.get_total(assetuuid)
                if position and total and SECONDS_MARGIN < position < total - SECONDS_MARGIN:
                    properties['resumetime'] = position
                    log(2, '[Metadata] manual resumetime set to %d' % position)

            duration = self.get_duration(api_data)
            if duration:
                properties['totaltime'] = duration

            episode = self.get_episode(api_data)
            season = self.get_season(api_data)
            if episode and season:
                properties['episodeno'] = 's%se%s' % (season, episode)

            year = self.get_year(api_data)
            if year:
                properties['year'] = year

        return properties
예제 #19
0
def get_addon_info(key):
    """Return addon information"""

    return statichelper.to_unicode(ADDON.getAddonInfo(key))
예제 #20
0
def get_property(key, window_id=10000):
    """Get a Window property"""
    return to_unicode(Window(window_id).getProperty(key))
예제 #21
0
def get_addon_info(key):
    """Return add-on information"""
    return to_unicode(ADDON.getAddonInfo(key))
예제 #22
0
    def get_context_menu(self, api_data, program, cache_file):
        ''' Get context menu '''
        from addon import plugin
        favorite_marker = ''
        watchlater_marker = ''
        context_menu = []

        # WATCH LATER
        if self._resumepoints.is_activated():
            assetpath = None

            # VRT NU Search API
            if api_data.get('type') == 'episode':
                program_title = api_data.get('program')
                assetpath = api_data.get('assetPath')

            # VRT NU Schedule API (some are missing vrt.whatson-id)
            elif api_data.get('vrt.whatson-id') or api_data.get('startTime'):
                program_title = api_data.get('title')
                assetpath = api_data.get('assetPath')

            if assetpath is not None:
                # We need to ensure forward slashes are quoted
                program_title = statichelper.to_unicode(
                    quote_plus(statichelper.from_unicode(program_title)))
                url = statichelper.url_to_episode(api_data.get('url', ''))
                assetuuid = self._resumepoints.assetpath_to_uuid(assetpath)
                if self._resumepoints.is_watchlater(assetuuid):
                    extras = dict()
                    # If we are in a watchlater menu, move cursor down before removing a favorite
                    if plugin.path.startswith('/resumepoints/watchlater'):
                        extras = dict(move_down=True)
                    # Unwatch context menu
                    context_menu.append(
                        (statichelper.capitalize(localize(30402)),
                         'RunPlugin(%s)' % url_for('unwatchlater',
                                                   uuid=assetuuid,
                                                   title=program_title,
                                                   url=url,
                                                   **extras)))
                    watchlater_marker = '[COLOR yellow]ᶫ[/COLOR]'
                else:
                    # Watch context menu
                    context_menu.append(
                        (statichelper.capitalize(localize(30401)),
                         'RunPlugin(%s)' % url_for('watchlater',
                                                   uuid=assetuuid,
                                                   title=program_title,
                                                   url=url)))

        # FOLLOW PROGRAM
        if self._favorites.is_activated():

            # VRT NU Search API
            if api_data.get('type') == 'episode':
                program_title = api_data.get('program')
                program_type = api_data.get('programType')
                follow_suffix = localize(
                    30410) if program_type != 'oneoff' else ''  # program
                follow_enabled = True

            # VRT NU Suggest API
            elif api_data.get('type') == 'program':
                program_title = api_data.get('title')
                follow_suffix = ''
                follow_enabled = True

            # VRT NU Schedule API (some are missing vrt.whatson-id)
            elif api_data.get('vrt.whatson-id') or api_data.get('startTime'):
                program_title = api_data.get('title')
                follow_suffix = localize(30410)  # program
                follow_enabled = bool(api_data.get('url'))

            if follow_enabled:
                program_title = statichelper.to_unicode(
                    quote_plus(statichelper.from_unicode(program_title))
                )  # We need to ensure forward slashes are quoted
                if self._favorites.is_favorite(program):
                    extras = dict()
                    # If we are in a favorites menu, move cursor down before removing a favorite
                    if plugin.path.startswith('/favorites'):
                        extras = dict(move_down=True)
                    context_menu.append((
                        localize(30412, title=follow_suffix),  # Unfollow
                        'RunPlugin(%s)' % url_for('unfollow',
                                                  program=program,
                                                  title=program_title,
                                                  **extras)))
                    favorite_marker = '[COLOR yellow]ᵛ[/COLOR]'
                else:
                    context_menu.append((
                        localize(30411, title=follow_suffix),  # Follow
                        'RunPlugin(%s)' % url_for(
                            'follow', program=program, title=program_title)))

        # GO TO PROGRAM
        if api_data.get('programType') != 'oneoff':
            if plugin.path.startswith(
                ('/favorites/offline', '/favorites/recent', '/offline',
                 '/recent', '/resumepoints/continue',
                 '/resumepoints/watchlater', '/tvguide')):
                context_menu.append((
                    localize(30417),  # Go to program
                    'Container.Update(%s)' %
                    url_for('programs', program=program, season='allseasons')))

        # REFRESH MENU
        context_menu.append((
            localize(30413),  # Refresh menu
            'RunPlugin(%s)' % url_for('delete_cache', cache_file=cache_file)))

        return context_menu, favorite_marker, watchlater_marker
예제 #23
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))))
예제 #24
0
def get_property(key, window_id=constants.WINDOW_HOME):
    """Get a Window property"""

    return statichelper.to_unicode(xbmcgui.Window(window_id).getProperty(key))
예제 #25
0
def get_addon_info(key):
    ''' Return add-on information '''
    return to_unicode(ADDON.getAddonInfo(key))
예제 #26
0
def get_property(key, window_id=10000):
    ''' Get a Window property '''
    return to_unicode(Window(window_id).getProperty(key))
예제 #27
0
def addon_name():
    ''' Cache and return VRT NU Add-on name '''
    if not hasattr(addon_name, 'cached'):
        from xbmcaddon import Addon
        addon_name.cached = to_unicode(Addon().getAddonInfo('name'))
    return addon_name.cached
예제 #28
0
def addon_fanart():
    ''' Cache and return VRT NU Add-on fanart '''
    if not hasattr(addon_fanart, 'cached'):
        from xbmcaddon import Addon
        addon_fanart.cached = to_unicode(Addon().getAddonInfo('fanart'))
    return addon_fanart.cached
예제 #29
0
def addon_id():
    ''' Cache and return VRT NU Add-on ID '''
    if not hasattr(addon_id, 'cached'):
        from xbmcaddon import Addon
        addon_id.cached = to_unicode(Addon().getAddonInfo('id'))
    return addon_id.cached