Fix checks and tests
This commit is contained in:
parent
007e684065
commit
f1463e9887
@ -7,7 +7,7 @@
|
|||||||
<import addon="script.module.requests" version="2.22.0"/>
|
<import addon="script.module.requests" version="2.22.0"/>
|
||||||
<import addon="script.module.routing" version="0.2.0"/>
|
<import addon="script.module.routing" version="0.2.0"/>
|
||||||
</requires>
|
</requires>
|
||||||
<extension point="xbmc.python.pluginsource" library="addon.py">
|
<extension point="xbmc.python.pluginsource" library="addon_entry.py">
|
||||||
<provides>video</provides>
|
<provides>video</provides>
|
||||||
</extension>
|
</extension>
|
||||||
<extension point="xbmc.addon.metadata">
|
<extension point="xbmc.addon.metadata">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Log handler for Kodi"""
|
"""Log handler for Kodi"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -113,17 +113,17 @@ def addon_profile():
|
|||||||
|
|
||||||
def url_for(name, *args, **kwargs):
|
def url_for(name, *args, **kwargs):
|
||||||
"""Wrapper for routing.url_for() to lookup by name"""
|
"""Wrapper for routing.url_for() to lookup by name"""
|
||||||
from resources.lib import addon
|
import addon # pylint: disable=import-error
|
||||||
return addon.routing.url_for(getattr(addon, name), *args, **kwargs)
|
return addon.routing.url_for(getattr(addon, name), *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def show_listing(title_items, category=None, sort=None, content=None, cache=True):
|
def show_listing(title_items, category=None, sort=None, content=None, cache=True):
|
||||||
""" Show a virtual directory in Kodi """
|
""" Show a virtual directory in Kodi """
|
||||||
from resources.lib import addon
|
from addon import routing # pylint: disable=import-error
|
||||||
|
|
||||||
if content:
|
if content:
|
||||||
# content is one of: files, songs, artists, albums, movies, tvshows, episodes, musicvideos, videos, images, games
|
# content is one of: files, songs, artists, albums, movies, tvshows, episodes, musicvideos, videos, images, games
|
||||||
xbmcplugin.setContent(addon.routing.handle, content=content)
|
xbmcplugin.setContent(routing.handle, content=content)
|
||||||
|
|
||||||
# Jump through hoops to get a stable breadcrumbs implementation
|
# Jump through hoops to get a stable breadcrumbs implementation
|
||||||
category_label = ''
|
category_label = ''
|
||||||
@ -137,7 +137,7 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True
|
|||||||
elif not content:
|
elif not content:
|
||||||
category_label = addon_name()
|
category_label = addon_name()
|
||||||
|
|
||||||
xbmcplugin.setPluginCategory(handle=addon.routing.handle, category=category_label)
|
xbmcplugin.setPluginCategory(handle=routing.handle, category=category_label)
|
||||||
|
|
||||||
# Add all sort methods to GUI (start with preferred)
|
# Add all sort methods to GUI (start with preferred)
|
||||||
if sort is None:
|
if sort is None:
|
||||||
@ -146,7 +146,7 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True
|
|||||||
sort = [sort] + DEFAULT_SORT_METHODS
|
sort = [sort] + DEFAULT_SORT_METHODS
|
||||||
|
|
||||||
for key in sort:
|
for key in sort:
|
||||||
xbmcplugin.addSortMethod(handle=addon.routing.handle, sortMethod=SORT_METHODS[key])
|
xbmcplugin.addSortMethod(handle=routing.handle, sortMethod=SORT_METHODS[key])
|
||||||
|
|
||||||
# Add the listings
|
# Add the listings
|
||||||
listing = []
|
listing = []
|
||||||
@ -184,13 +184,13 @@ def show_listing(title_items, category=None, sort=None, content=None, cache=True
|
|||||||
url = title_item.path if title_item.path else None
|
url = title_item.path if title_item.path else None
|
||||||
listing.append((url, list_item, is_folder))
|
listing.append((url, list_item, is_folder))
|
||||||
|
|
||||||
succeeded = xbmcplugin.addDirectoryItems(addon.routing.handle, listing, len(listing))
|
succeeded = xbmcplugin.addDirectoryItems(routing.handle, listing, len(listing))
|
||||||
xbmcplugin.endOfDirectory(addon.routing.handle, succeeded, cacheToDisc=cache)
|
xbmcplugin.endOfDirectory(routing.handle, succeeded, cacheToDisc=cache)
|
||||||
|
|
||||||
|
|
||||||
def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None):
|
def play(stream, title=None, art_dict=None, info_dict=None, prop_dict=None):
|
||||||
"""Play the given stream"""
|
"""Play the given stream"""
|
||||||
from resources.lib.addon import routing
|
from addon import routing # pylint: disable=import-error
|
||||||
|
|
||||||
play_item = xbmcgui.ListItem(label=title, path=stream)
|
play_item = xbmcgui.ListItem(label=title, path=stream)
|
||||||
if art_dict:
|
if art_dict:
|
||||||
@ -476,7 +476,7 @@ def container_update(url):
|
|||||||
|
|
||||||
def end_of_directory():
|
def end_of_directory():
|
||||||
"""Close a virtual directory, required to avoid a waiting Kodi"""
|
"""Close a virtual directory, required to avoid a waiting Kodi"""
|
||||||
from resources.lib.addon import routing
|
from addon import routing # pylint: disable=import-error
|
||||||
xbmcplugin.endOfDirectory(handle=routing.handle, succeeded=False, updateListing=False, cacheToDisc=False)
|
xbmcplugin.endOfDirectory(handle=routing.handle, succeeded=False, updateListing=False, cacheToDisc=False)
|
||||||
|
|
||||||
|
|
||||||
@ -510,8 +510,8 @@ def get_cache(key, ttl=None):
|
|||||||
""" Get an item from the cache """
|
""" Get an item from the cache """
|
||||||
import time
|
import time
|
||||||
path = get_cache_path()
|
path = get_cache_path()
|
||||||
file = '.'.join(key)
|
filename = '.'.join(key)
|
||||||
fullpath = path + file
|
fullpath = path + filename
|
||||||
|
|
||||||
if not exists(fullpath):
|
if not exists(fullpath):
|
||||||
return None
|
return None
|
||||||
@ -521,7 +521,7 @@ def get_cache(key, ttl=None):
|
|||||||
|
|
||||||
with open_file(fullpath, 'r') as fdesc:
|
with open_file(fullpath, 'r') as fdesc:
|
||||||
try:
|
try:
|
||||||
_LOGGER.info('Fetching {file} from cache', file=file)
|
_LOGGER.info('Fetching {file} from cache', file=filename)
|
||||||
import json
|
import json
|
||||||
value = json.load(fdesc)
|
value = json.load(fdesc)
|
||||||
return value
|
return value
|
||||||
@ -532,13 +532,13 @@ def get_cache(key, ttl=None):
|
|||||||
def set_cache(key, data):
|
def set_cache(key, data):
|
||||||
""" Store an item in the cache """
|
""" Store an item in the cache """
|
||||||
path = get_cache_path()
|
path = get_cache_path()
|
||||||
file = '.'.join(key)
|
filename = '.'.join(key)
|
||||||
fullpath = path + file
|
fullpath = path + filename
|
||||||
|
|
||||||
if not exists(path):
|
if not exists(path):
|
||||||
mkdirs(path)
|
mkdirs(path)
|
||||||
|
|
||||||
with open_file(fullpath, 'w') as fdesc:
|
with open_file(fullpath, 'w') as fdesc:
|
||||||
_LOGGER.info('Storing to cache as {file}', file=file)
|
_LOGGER.info('Storing to cache as {file}', file=filename)
|
||||||
import json
|
import json
|
||||||
json.dump(data, fdesc)
|
json.dump(data, fdesc)
|
||||||
|
@ -70,7 +70,7 @@ class Catalog:
|
|||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(program.episodes) == 0:
|
if not program.episodes:
|
||||||
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the Vier/Vijf/Zes catalogue.
|
kodiutils.ok_dialog(message=kodiutils.localize(30717)) # This program is not available in the Vier/Vijf/Zes catalogue.
|
||||||
kodiutils.end_of_directory()
|
kodiutils.end_of_directory()
|
||||||
return
|
return
|
||||||
@ -87,37 +87,41 @@ class Catalog:
|
|||||||
# Add an '* All seasons' entry when configured in Kodi
|
# Add an '* All seasons' entry when configured in Kodi
|
||||||
if kodiutils.get_global_setting('videolibrary.showallitems') is True:
|
if kodiutils.get_global_setting('videolibrary.showallitems') is True:
|
||||||
listing.append(
|
listing.append(
|
||||||
TitleItem(title='* %s' % kodiutils.localize(30204), # * All seasons
|
TitleItem(
|
||||||
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=-1),
|
title='* %s' % kodiutils.localize(30204), # * All seasons
|
||||||
art_dict={
|
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=-1),
|
||||||
'thumb': program.cover,
|
art_dict={
|
||||||
'fanart': program.background,
|
'thumb': program.cover,
|
||||||
},
|
'fanart': program.background,
|
||||||
info_dict={
|
},
|
||||||
'tvshowtitle': program.title,
|
info_dict={
|
||||||
'title': kodiutils.localize(30204), # All seasons
|
'tvshowtitle': program.title,
|
||||||
'plot': program.description,
|
'title': kodiutils.localize(30204), # All seasons
|
||||||
'set': program.title,
|
'plot': program.description,
|
||||||
'studio': studio,
|
'set': program.title,
|
||||||
})
|
'studio': studio,
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add the seasons
|
# Add the seasons
|
||||||
for s in list(program.seasons.values()):
|
for s in list(program.seasons.values()):
|
||||||
listing.append(
|
listing.append(
|
||||||
TitleItem(title=s.title, # kodiutils.localize(30205, season=s.number), # Season {season}
|
TitleItem(
|
||||||
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=s.number),
|
title=s.title, # kodiutils.localize(30205, season=s.number), # Season {season}
|
||||||
art_dict={
|
path=kodiutils.url_for('show_catalog_program_season', channel=channel, program=program_id, season=s.number),
|
||||||
'thumb': s.cover,
|
art_dict={
|
||||||
'fanart': program.background,
|
'thumb': s.cover,
|
||||||
},
|
'fanart': program.background,
|
||||||
info_dict={
|
},
|
||||||
'tvshowtitle': program.title,
|
info_dict={
|
||||||
'title': kodiutils.localize(30205, season=s.number), # Season {season}
|
'tvshowtitle': program.title,
|
||||||
'plot': s.description,
|
'title': kodiutils.localize(30205, season=s.number), # Season {season}
|
||||||
'set': program.title,
|
'plot': s.description,
|
||||||
'studio': studio,
|
'set': program.title,
|
||||||
})
|
'studio': studio,
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sort by label. Some programs return seasons unordered.
|
# Sort by label. Some programs return seasons unordered.
|
||||||
|
@ -38,21 +38,23 @@ class Channels:
|
|||||||
]
|
]
|
||||||
|
|
||||||
listing.append(
|
listing.append(
|
||||||
TitleItem(title=channel.get('name'),
|
TitleItem(
|
||||||
path=kodiutils.url_for('show_channel_menu', channel=key),
|
title=channel.get('name'),
|
||||||
art_dict={
|
path=kodiutils.url_for('show_channel_menu', channel=key),
|
||||||
'icon': icon,
|
art_dict={
|
||||||
'thumb': icon,
|
'icon': icon,
|
||||||
'fanart': fanart,
|
'thumb': icon,
|
||||||
},
|
'fanart': fanart,
|
||||||
info_dict={
|
},
|
||||||
'plot': None,
|
info_dict={
|
||||||
'playcount': 0,
|
'plot': None,
|
||||||
'mediatype': 'video',
|
'playcount': 0,
|
||||||
'studio': channel.get('studio_icon'),
|
'mediatype': 'video',
|
||||||
},
|
'studio': channel.get('studio_icon'),
|
||||||
stream_dict=STREAM_DICT,
|
},
|
||||||
context_menu=context_menu),
|
stream_dict=STREAM_DICT,
|
||||||
|
context_menu=context_menu
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
kodiutils.show_listing(listing, 30007)
|
kodiutils.show_listing(listing, 30007)
|
||||||
@ -68,35 +70,41 @@ class Channels:
|
|||||||
fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel.get('background'))
|
fanart = '{path}/resources/logos/{logo}'.format(path=kodiutils.addon_path(), logo=channel.get('background'))
|
||||||
|
|
||||||
listing = [
|
listing = [
|
||||||
TitleItem(title=kodiutils.localize(30053, channel=channel.get('name')), # TV Guide for {channel}
|
TitleItem(
|
||||||
path=kodiutils.url_for('show_tvguide_channel', channel=key),
|
title=kodiutils.localize(30053, channel=channel.get('name')), # TV Guide for {channel}
|
||||||
art_dict={
|
path=kodiutils.url_for('show_tvguide_channel', channel=key),
|
||||||
'icon': 'DefaultAddonTvInfo.png',
|
art_dict={
|
||||||
'fanart': fanart,
|
'icon': 'DefaultAddonTvInfo.png',
|
||||||
},
|
'fanart': fanart,
|
||||||
info_dict={
|
},
|
||||||
'plot': kodiutils.localize(30054, channel=channel.get('name')), # Browse the TV Guide for {channel}
|
info_dict={
|
||||||
}),
|
'plot': kodiutils.localize(30054, channel=channel.get('name')), # Browse the TV Guide for {channel}
|
||||||
TitleItem(title=kodiutils.localize(30055, channel=channel.get('name')), # Catalog for {channel}
|
}
|
||||||
path=kodiutils.url_for('show_catalog_channel', channel=key),
|
),
|
||||||
art_dict={
|
TitleItem(
|
||||||
'icon': 'DefaultMovieTitle.png',
|
title=kodiutils.localize(30055, channel=channel.get('name')), # Catalog for {channel}
|
||||||
'fanart': fanart,
|
path=kodiutils.url_for('show_catalog_channel', channel=key),
|
||||||
},
|
art_dict={
|
||||||
info_dict={
|
'icon': 'DefaultMovieTitle.png',
|
||||||
'plot': kodiutils.localize(30056, channel=channel.get('name')), # Browse the Catalog for {channel}
|
'fanart': fanart,
|
||||||
})
|
},
|
||||||
|
info_dict={
|
||||||
|
'plot': kodiutils.localize(30056, channel=channel.get('name')), # Browse the Catalog for {channel}
|
||||||
|
}
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add YouTube channels
|
# Add YouTube channels
|
||||||
if kodiutils.get_cond_visibility('System.HasAddon(plugin.video.youtube)') != 0:
|
if kodiutils.get_cond_visibility('System.HasAddon(plugin.video.youtube)') != 0:
|
||||||
for youtube in channel.get('youtube', []):
|
for youtube in channel.get('youtube', []):
|
||||||
listing.append(
|
listing.append(
|
||||||
TitleItem(title=kodiutils.localize(30206, label=youtube.get('label')), # Watch {label} on YouTube
|
TitleItem(
|
||||||
path=youtube.get('path'),
|
title=kodiutils.localize(30206, label=youtube.get('label')), # Watch {label} on YouTube
|
||||||
info_dict={
|
path=youtube.get('path'),
|
||||||
'plot': kodiutils.localize(30206, label=youtube.get('label')), # Watch {label} on YouTube
|
info_dict={
|
||||||
})
|
'plot': kodiutils.localize(30206, label=youtube.get('label')), # Watch {label} on YouTube
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
kodiutils.show_listing(listing, 30007, sort=['unsorted'])
|
kodiutils.show_listing(listing, 30007, sort=['unsorted'])
|
||||||
|
@ -19,33 +19,39 @@ class Menu:
|
|||||||
def show_mainmenu():
|
def show_mainmenu():
|
||||||
""" Show the main menu """
|
""" Show the main menu """
|
||||||
listing = [
|
listing = [
|
||||||
TitleItem(title=kodiutils.localize(30001), # A-Z
|
TitleItem(
|
||||||
path=kodiutils.url_for('show_catalog'),
|
title=kodiutils.localize(30001), # A-Z
|
||||||
art_dict=dict(
|
path=kodiutils.url_for('show_catalog'),
|
||||||
icon='DefaultMovieTitle.png',
|
art_dict=dict(
|
||||||
fanart=kodiutils.get_addon_info('fanart'),
|
icon='DefaultMovieTitle.png',
|
||||||
),
|
fanart=kodiutils.get_addon_info('fanart'),
|
||||||
info_dict=dict(
|
),
|
||||||
plot=kodiutils.localize(30002),
|
info_dict=dict(
|
||||||
)),
|
plot=kodiutils.localize(30002),
|
||||||
TitleItem(title=kodiutils.localize(30007), # TV Channels
|
)
|
||||||
path=kodiutils.url_for('show_channels'),
|
),
|
||||||
art_dict=dict(
|
TitleItem(
|
||||||
icon='DefaultAddonPVRClient.png',
|
title=kodiutils.localize(30007), # TV Channels
|
||||||
fanart=kodiutils.get_addon_info('fanart'),
|
path=kodiutils.url_for('show_channels'),
|
||||||
),
|
art_dict=dict(
|
||||||
info_dict=dict(
|
icon='DefaultAddonPVRClient.png',
|
||||||
plot=kodiutils.localize(30008),
|
fanart=kodiutils.get_addon_info('fanart'),
|
||||||
)),
|
),
|
||||||
TitleItem(title=kodiutils.localize(30009), # Search
|
info_dict=dict(
|
||||||
path=kodiutils.url_for('show_search'),
|
plot=kodiutils.localize(30008),
|
||||||
art_dict=dict(
|
)
|
||||||
icon='DefaultAddonsSearch.png',
|
),
|
||||||
fanart=kodiutils.get_addon_info('fanart'),
|
TitleItem(
|
||||||
),
|
title=kodiutils.localize(30009), # Search
|
||||||
info_dict=dict(
|
path=kodiutils.url_for('show_search'),
|
||||||
plot=kodiutils.localize(30010),
|
art_dict=dict(
|
||||||
))
|
icon='DefaultAddonsSearch.png',
|
||||||
|
fanart=kodiutils.get_addon_info('fanart'),
|
||||||
|
),
|
||||||
|
info_dict=dict(
|
||||||
|
plot=kodiutils.localize(30010),
|
||||||
|
)
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
kodiutils.show_listing(listing, sort=['unsorted'])
|
kodiutils.show_listing(listing, sort=['unsorted'])
|
||||||
|
@ -72,11 +72,12 @@ class AuthApi:
|
|||||||
|
|
||||||
# Store new tokens in cache
|
# Store new tokens in cache
|
||||||
with open(self._cache + self.TOKEN_FILE, 'wb') as f:
|
with open(self._cache + self.TOKEN_FILE, 'wb') as f:
|
||||||
f.write(json.dumps(dict(
|
data = json.dumps(dict(
|
||||||
id_token=self._id_token,
|
id_token=self._id_token,
|
||||||
refresh_token=self._refresh_token,
|
refresh_token=self._refresh_token,
|
||||||
expiry=self._expiry,
|
expiry=self._expiry,
|
||||||
)))
|
))
|
||||||
|
f.write(data.encode('utf8'))
|
||||||
|
|
||||||
return self._id_token
|
return self._id_token
|
||||||
|
|
||||||
|
@ -185,10 +185,11 @@ class AwsIdp:
|
|||||||
secret_block_bytes = base64.standard_b64decode(secret_block)
|
secret_block_bytes = base64.standard_b64decode(secret_block)
|
||||||
|
|
||||||
# the message is a combo of the pool_id, provided SRP userId, the Secret and Timestamp
|
# the message is a combo of the pool_id, provided SRP userId, the Secret and Timestamp
|
||||||
msg = bytearray(self.pool_id.split('_')[1], 'utf-8') + \
|
msg = \
|
||||||
bytearray(user_id_for_srp, 'utf-8') + \
|
bytearray(self.pool_id.split('_')[1], 'utf-8') + \
|
||||||
bytearray(secret_block_bytes) + \
|
bytearray(user_id_for_srp, 'utf-8') + \
|
||||||
bytearray(timestamp, 'utf-8')
|
bytearray(secret_block_bytes) + \
|
||||||
|
bytearray(timestamp, 'utf-8')
|
||||||
hmac_obj = hmac.new(hkdf, msg, digestmod=hashlib.sha256)
|
hmac_obj = hmac.new(hkdf, msg, digestmod=hashlib.sha256)
|
||||||
signature_string = base64.standard_b64encode(hmac_obj.digest()).decode('utf-8')
|
signature_string = base64.standard_b64encode(hmac_obj.digest()).decode('utf-8')
|
||||||
challenge_request = {
|
challenge_request = {
|
||||||
|
@ -8,8 +8,8 @@ import logging
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import requests
|
|
||||||
from six.moves.html_parser import HTMLParser
|
from six.moves.html_parser import HTMLParser
|
||||||
|
import requests
|
||||||
|
|
||||||
from resources.lib.viervijfzes import CHANNELS
|
from resources.lib.viervijfzes import CHANNELS
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ class SearchApi:
|
|||||||
:type query: str
|
:type query: str
|
||||||
:rtype list[Program]
|
:rtype list[Program]
|
||||||
"""
|
"""
|
||||||
|
if not query:
|
||||||
|
return []
|
||||||
|
|
||||||
response = self._session.post(
|
response = self._session.post(
|
||||||
self.API_ENDPOINT,
|
self.API_ENDPOINT,
|
||||||
json={
|
json={
|
||||||
@ -35,10 +38,11 @@ class SearchApi:
|
|||||||
"mode": "byDate"
|
"mode": "byDate"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
data = json.loads(response.content)
|
|
||||||
|
|
||||||
if data['timed_out']:
|
if response.status_code != 200:
|
||||||
raise TimeoutError()
|
raise Exception('Could not search')
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for hit in data['hits']['hits']:
|
for hit in data['hits']['hits']:
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" Tests """
|
""" Tests """
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
@ -132,6 +132,7 @@ class Player:
|
|||||||
''' A stub implementation for the xbmc Player class getPlayingFile() method '''
|
''' A stub implementation for the xbmc Player class getPlayingFile() method '''
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class VideoInfoTag:
|
class VideoInfoTag:
|
||||||
''' A stub implementation of the xbmc VideoInfoTag class '''
|
''' A stub implementation of the xbmc VideoInfoTag class '''
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user