Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Implement program caching for more metadata in listings #8

Merged
merged 6 commits into from
Mar 22, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<extension point="xbmc.python.pluginsource" library="addon_entry.py">
<provides>video</provides>
</extension>
<extension point="xbmc.service" library="service_entry.py"/>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Watch content from VIER, VIJF and ZES.</summary>
<platform>all</platform>
Expand All @@ -22,6 +23,6 @@
<icon>resources/icon.png</icon>
<fanart>resources/fanart.png</fanart>
</assets>
<reuselanguageinvoker>true</reuselanguageinvoker>
michaelarnauts marked this conversation as resolved.
Show resolved Hide resolved
<!-- <reuselanguageinvoker>true</reuselanguageinvoker>-->
</extension>
</addon>
33 changes: 33 additions & 0 deletions resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ msgctxt "#30713"
msgid "The requested video was not found in the guide."
msgstr ""

msgctxt "#30714"
msgid "Local metadata is cleared."
msgstr ""

msgctxt "#30715"
msgid "Updating metadata"
msgstr ""

msgctxt "#30716"
msgid "Updating metadata ({index}/{total})..."
msgstr ""

msgctxt "#30717"
msgid "This program is not available in the catalogue."
msgstr ""
Expand All @@ -141,3 +153,24 @@ msgstr ""
msgctxt "#30805"
msgid "Password"
msgstr ""

msgctxt "#30820"
msgid "Interface"
msgstr ""

msgctxt "#30827"
msgid "Metadata"
msgstr ""

msgctxt "#30829"
msgid "Periodically refresh metadata in the background"
msgstr ""

msgctxt "#30831"
msgid "Update local metadata now"
msgstr ""

msgctxt "#30833"
msgid "Clear local metadata"
msgstr ""

33 changes: 33 additions & 0 deletions resources/language/resource.language.nl_nl/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ msgctxt "#30713"
msgid "The requested video was not found in the guide."
msgstr "De gevraagde video werd niet gevonden in de tv-gids."

msgctxt "#30714"
msgid "Local metadata is cleared."
msgstr "De locale metadata is verwijderd."

msgctxt "#30715"
msgid "Updating metadata"
msgstr "Vernieuwen metadata"

msgctxt "#30716"
msgid "Updating metadata ({index}/{total})..."
msgstr "Vernieuwen metadata ({index}/{total})..."

msgctxt "#30717"
msgid "This program is not available in the catalogue."
msgstr "Dit programma is niet beschikbaar in de catalogus."
Expand All @@ -142,3 +154,24 @@ msgstr "E-mailadres"
msgctxt "#30805"
msgid "Password"
msgstr "Wachtwoord"

msgctxt "#30820"
msgid "Interface"
msgstr "Interface"

msgctxt "#30827"
msgid "Metadata"
msgstr "Metadata"

msgctxt "#30829"
msgid "Periodically refresh metadata in the background"
msgstr "Vernieuw de metdata automatisch in de achtergrond"

msgctxt "#30831"
msgid "Update local metadata now"
msgstr "De locale metadata nu vernieuwen"

msgctxt "#30833"
msgid "Clear local metadata"
msgstr "De locale metadata verwijderen"

23 changes: 20 additions & 3 deletions resources/lib/addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@

from __future__ import absolute_import, division, unicode_literals

import logging

from routing import Plugin

from resources.lib import kodilogging

kodilogging.config()
routing = Plugin()
_LOGGER = logging.getLogger('addon')


@routing.route('/')
Expand Down Expand Up @@ -82,11 +85,11 @@ def show_search(query=None):
Search().show_search(query)


@routing.route('/play/catalog/<channel>/<uuid>')
def play(channel, uuid):
@routing.route('/play/catalog/<uuid>')
def play(uuid):
""" Play the requested item """
from resources.lib.modules.player import Player
Player().play(channel, uuid)
Player().play(uuid)


@routing.route('/play/page/<channel>/<page>')
Expand All @@ -101,6 +104,20 @@ def play_from_page(channel, page):
Player().play_from_page(channel, unquote(page))


@routing.route('/metadata/update')
def metadata_update():
""" Update the metadata for the listings (called from settings) """
from resources.lib.modules.metadata import Metadata
Metadata().update()


@routing.route('/metadata/clean')
def metadata_clean():
""" Clear metadata (called from settings) """
from resources.lib.modules.metadata import Metadata
Metadata().clean()


def run(params):
""" Run the routing plugin """
routing.run(params)
31 changes: 23 additions & 8 deletions resources/lib/kodiutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def set_locale():
setlocale(LC_ALL, locale_lang)
except (Error, ValueError) as exc:
if locale_lang != 'en_GB':
_LOGGER.debug("Your system does not support locale '{locale}': {error}", locale=locale_lang, error=exc)
_LOGGER.debug("Your system does not support locale '%s': %s", locale_lang, exc)
set_locale.cached = False
return False
set_locale.cached = True
Expand Down Expand Up @@ -423,14 +423,14 @@ def listdir(path):
def mkdir(path):
"""Create a directory (using xbmcvfs)"""
from xbmcvfs import mkdir as vfsmkdir
_LOGGER.debug("Create directory '{path}'.", path=path)
_LOGGER.debug("Create directory '%s'.", path)
return vfsmkdir(path)


def mkdirs(path):
"""Create directory including parents (using xbmcvfs)"""
from xbmcvfs import mkdirs as vfsmkdirs
_LOGGER.debug("Recursively create directory '{path}'.", path=path)
_LOGGER.debug("Recursively create directory '%s'.", path)
return vfsmkdirs(path)


Expand Down Expand Up @@ -458,14 +458,14 @@ def stat_file(path):
def delete(path):
"""Remove a file (using xbmcvfs)"""
from xbmcvfs import delete as vfsdelete
_LOGGER.debug("Delete file '{path}'.", path=path)
_LOGGER.debug("Delete file '%s'.", path)
return vfsdelete(path)


def container_refresh(url=None):
"""Refresh the current container or (re)load a container by URL"""
if url:
_LOGGER.debug('Execute: Container.Refresh({url})', url=url)
_LOGGER.debug('Execute: Container.Refresh(%s)', url)
xbmc.executebuiltin('Container.Refresh({url})'.format(url=url))
else:
_LOGGER.debug('Execute: Container.Refresh')
Expand All @@ -475,7 +475,7 @@ def container_refresh(url=None):
def container_update(url):
"""Update the current container while respecting the path history."""
if url:
_LOGGER.debug('Execute: Container.Update({url})', url=url)
_LOGGER.debug('Execute: Container.Update(%s)', url)
xbmc.executebuiltin('Container.Update({url})'.format(url=url))
else:
# URL is a mandatory argument for Container.Update, use Container.Refresh instead
Expand Down Expand Up @@ -529,7 +529,7 @@ def get_cache(key, ttl=None):

with open_file(fullpath, 'r') as fdesc:
try:
_LOGGER.info('Fetching {file} from cache', file=filename)
_LOGGER.debug('Fetching %s from cache', filename)
import json
value = json.load(fdesc)
return value
Expand All @@ -547,6 +547,21 @@ def set_cache(key, data):
mkdirs(path)

with open_file(fullpath, 'w') as fdesc:
_LOGGER.info('Storing to cache as {file}', file=filename)
_LOGGER.debug('Storing to cache as %s', filename)
import json
json.dump(data, fdesc)


def invalidate_cache(ttl=None):
""" Clear the cache """
path = get_cache_path()
if not exists(path):
return
_, files = listdir(path)
import time
now = time.mktime(time.localtime())
for filename in files:
fullpath = path + filename
if ttl and now - stat_file(fullpath).st_mtime() < ttl:
continue
delete(fullpath)
4 changes: 3 additions & 1 deletion resources/lib/modules/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from resources.lib.kodiutils import TitleItem
from resources.lib.modules.menu import Menu
from resources.lib.viervijfzes import CHANNELS
from resources.lib.viervijfzes.auth import AuthApi
from resources.lib.viervijfzes.content import ContentApi, UnavailableException

_LOGGER = logging.getLogger('catalog')
Expand All @@ -19,7 +20,8 @@ class Catalog:

def __init__(self):
""" Initialise object """
self._api = ContentApi()
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'))
self._api = ContentApi(auth)
self._menu = Menu()

def show_catalog(self):
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/modules/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def generate_titleitem(item):
})

return TitleItem(title=info_dict['title'],
path=kodiutils.url_for('play', channel=item.channel, uuid=item.uuid),
path=kodiutils.url_for('play', uuid=item.uuid),
art_dict=art_dict,
info_dict=info_dict,
stream_dict=stream_dict,
Expand Down
60 changes: 60 additions & 0 deletions resources/lib/modules/metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
""" Metadata module """

from __future__ import absolute_import, division, unicode_literals

from resources.lib import kodiutils
from resources.lib.viervijfzes import CHANNELS
from resources.lib.viervijfzes.content import ContentApi, Program


class Metadata:
""" Code responsible for the management of the local cached metadata """

def __init__(self):
""" Initialise object """
self._api = ContentApi()

def update(self):
""" Update the metadata with a foreground progress indicator """
# Create progress indicator
progress = kodiutils.progress(message=kodiutils.localize(30715)) # Updating metadata

def update_status(i, total):
""" Update the progress indicator """
progress.update(int(((i + 1) / total) * 100), kodiutils.localize(30716, index=i + 1, total=total)) # Updating metadata ({index}/{total})
return progress.iscanceled()

self.fetch_metadata(callback=update_status)

# Close progress indicator
progress.close()

def fetch_metadata(self, callback=None):
""" Fetch the metadata for all the items in the catalog
:type callback: callable
"""
# Fetch all items from the catalog
items = []
for channel in list(CHANNELS):
items.extend(self._api.get_programs(channel))
count = len(items)

# Loop over all of them and download the metadata
for index, item in enumerate(items):
if isinstance(item, Program):
self._api.get_program(item.channel, item.path)

# Run callback after every item
if callback and callback(index, count):
# Stop when callback returns False
return False

return True

@staticmethod
def clean():
""" Clear metadata (called from settings) """
kodiutils.invalidate_cache()
kodiutils.set_setting('metadata_last_updated', '0')
kodiutils.ok_dialog(message=kodiutils.localize(30714)) # Local metadata is cleared
15 changes: 7 additions & 8 deletions resources/lib/modules/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ def play_from_page(self, channel, path):
episode = ContentApi().get_episode(channel, path)

# Play this now we have the uuid
self.play(channel, episode.uuid)
self.play(episode.uuid)

@staticmethod
def play(channel, item):
def play(item):
""" Play the requested item.
:type channel: string
:type item: string
"""
try:
Expand All @@ -48,17 +47,17 @@ def play(channel, item):

# Fetch an auth token now
try:
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'), kodiutils.get_tokens_path())
token = auth.get_token()
auth = AuthApi(kodiutils.get_setting('username'), kodiutils.get_setting('password'))

# Get stream information
resolved_stream = ContentApi(auth).get_stream_by_uuid(item)

except (InvalidLoginException, AuthenticationException) as ex:
_LOGGER.error(ex)
kodiutils.ok_dialog(message=kodiutils.localize(30702, error=ex.message))
kodiutils.end_of_directory()
return

# Get stream information
resolved_stream = ContentApi(token).get_stream(channel, item)

except GeoblockedException:
kodiutils.ok_dialog(heading=kodiutils.localize(30709), message=kodiutils.localize(30710)) # This video is geo-blocked...
return
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/modules/tvguide.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,4 @@ def play_epg_datetime(self, channel, timestamp):
return

kodiutils.container_update(
kodiutils.url_for('play', channel=channel, uuid=broadcast.video_url))
kodiutils.url_for('play', uuid=broadcast.video_url))
Loading