Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[metadata.tvmaze@matrix] 1.3.5 #528

Merged
merged 1 commit into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 2 additions & 3 deletions metadata.tvmaze/addon.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="metadata.tvmaze"
name="TVmaze"
version="1.3.4"
version="1.3.5"
provider-name="Roman V.M.">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
Expand All @@ -20,8 +20,7 @@ We provide an API that can be used by anyone or service like Kodi to retrieve TV
</assets>
<website>https://www.tvmaze.com</website>
<source>https://github.com/romanvm/kodi.tvmaze</source>
<news>1.3.4:
- Internal changes.
<news>1.3.4: Fix incompatibility with filename tags in Kodi "Omega".
</news>
<reuselanguageinvoker>true</reuselanguageinvoker>
</extension>
Expand Down
42 changes: 26 additions & 16 deletions metadata.tvmaze/libs/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"""Plugin route actions"""

import json
import logging
import sys
from typing import Optional
from urllib import parse as urllib_parse
Expand All @@ -24,7 +25,7 @@
import xbmcplugin

from . import tvmaze_api, data_service
from .utils import logger, get_episode_order, ADDON
from .utils import get_episode_order, ADDON

HANDLE = int(sys.argv[1])

Expand Down Expand Up @@ -60,7 +61,7 @@ def parse_nfo_file(nfo: str, full_nfo: bool):
:param full_nfo: use the info from an NFO and not to try to get the info by the scraper
"""
is_tvshow_nfo = True
logger.debug(f'Trying to parse NFO file:\n{nfo}')
logging.debug('Trying to parse NFO file:\n%s', nfo)
info = None
if '<episodedetails>' in nfo:
if full_nfo:
Expand Down Expand Up @@ -94,33 +95,40 @@ def parse_nfo_file(nfo: str, full_nfo: bool):
)


def get_details(show_id: str, default_rating: str) -> None:
def get_details(show_id: Optional[str], default_rating: str, unique_ids: Optional[str] = None) -> None:
"""Get details about a specific show"""
logger.debug(f'Getting details for show id {show_id}')
logging.debug('Getting details for show id %s', show_id)
if not show_id and unique_ids is not None:
show_id = data_service.parse_json_episogeguide(unique_ids)
if not show_id:
xbmcplugin.setResolvedUrl(HANDLE, False, xbmcgui.ListItem(offscreen=True))
return
show_info = tvmaze_api.load_show_info(show_id)
if show_info is not None:
list_item = xbmcgui.ListItem(show_info['name'], offscreen=True)
list_item = data_service.add_main_show_info(list_item, show_info,
default_rating=default_rating)
xbmcplugin.setResolvedUrl(HANDLE, True, list_item)
else:
xbmcplugin.setResolvedUrl(HANDLE, False, xbmcgui.ListItem(offscreen=True))
return
xbmcplugin.setResolvedUrl(HANDLE, False, xbmcgui.ListItem(offscreen=True))


def get_episode_list(episodeguide: str, episode_order: str) -> None: # pylint: disable=missing-docstring
logger.debug(f'Getting episode list for episodeguide {episodeguide}, order: {episode_order}')
logging.debug('Getting episode list for episodeguide %s, order: %s',
episodeguide, episode_order)
show_id = None
if episodeguide.startswith('{'):
show_id = data_service.parse_json_episogeguide(episodeguide)
if show_id is None:
logger.error(f'Unable to determine TVmaze show ID from episodeguide: {episodeguide}')
logging.error(f'Unable to determine TVmaze show ID from episodeguide: %s', episodeguide)
return
if show_id is None and not episodeguide.isdigit():
logger.warning(f'Invalid episodeguide format: {episodeguide} (probably URL).')
logging.warning('Invalid episodeguide format: %s (probably URL).', episodeguide)
show_id = data_service.parse_url_episodeguide(episodeguide)
if show_id is None and episodeguide.isdigit():
logger.warning(f'Invalid episodeguide format: {episodeguide} (a numeric string). '
f'Please consider re-scanning the show to update episodeguide record.')
logging.warning('Invalid episodeguide format: %s (a numeric string). '
'Please consider re-scanning the show to update episodeguide record.',
episodeguide)
show_id = episodeguide
if show_id is not None:
episodes_map = data_service.get_episodes_map(show_id, episode_order)
Expand All @@ -147,7 +155,7 @@ def get_episode_list(episodeguide: str, episode_order: str) -> None: # pylint:
def get_episode_details(encoded_ids: str, episode_order: str) -> None: # pylint: disable=missing-docstring
encoded_ids = urllib_parse.unquote(encoded_ids)
decoded_ids = dict(urllib_parse.parse_qsl(encoded_ids))
logger.debug(f'Getting episode details for {decoded_ids}')
logging.debug('Getting episode details for %s', decoded_ids)
episode_info = data_service.get_episode_info(decoded_ids['show_id'],
decoded_ids['episode_id'],
decoded_ids['season'],
Expand All @@ -167,7 +175,7 @@ def get_artwork(show_id: str) -> None:

:param show_id: default unique ID set by setUniqueIDs() method
"""
logger.debug(f'Getting artwork for show ID {show_id}')
logging.debug('Getting artwork for show ID %s', show_id)
if show_id:
show_info = tvmaze_api.load_show_info(show_id)
if show_info is not None:
Expand All @@ -186,9 +194,9 @@ def router(paramstring: str) -> None:
:raises RuntimeError: on unknown call action
"""
params = dict(urllib_parse.parse_qsl(paramstring))
logger.debug(f'Called addon with params: {sys.argv}')
logging.debug('Called addon with params: %s', str(sys.argv))
path_settings = json.loads(params.get('pathSettings') or '{}')
logger.debug(f'Path settings: {path_settings}')
logging.debug('Path settings: %s', path_settings)
episode_order = get_episode_order(path_settings)
default_rating = path_settings.get('default_rating')
if default_rating is None:
Expand All @@ -201,7 +209,9 @@ def router(paramstring: str) -> None:
elif params['action'].lower() == 'nfourl':
parse_nfo_file(params['nfo'], full_nfo)
elif params['action'] == 'getdetails':
get_details(params['url'], default_rating)
url = params.get('url')
unique_ids = params.get('uniqueIDs')
get_details(url, default_rating, unique_ids)
elif params['action'] == 'getepisodelist':
get_episode_list(params['url'], episode_order)
elif params['action'] == 'getepisodedetails':
Expand Down
17 changes: 9 additions & 8 deletions metadata.tvmaze/libs/cache_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@
"""Cache-related functionality"""

import json
import logging
import os
import time
from typing import Optional, Text, Dict, Any, Union

import xbmcgui
import xbmcvfs

from .utils import ADDON_ID, logger
from .utils import ADDON_ID

EPISODES_CACHE_TTL = 60 * 10 # 10 minutes


class MemoryCache:
_instance = None
CACHE_KEY = '__tvmaze_scraper__'
CACHE_KEY = f'__{ADDON_ID}_cache__'

def __new__(cls):
if cls._instance is None:
Expand All @@ -52,17 +53,17 @@ def set(self, obj_id: Union[int, str], obj: Any) -> None:
def get(self, obj_id: Union[int, str]) -> Optional[Any]:
cache_json = self._window.getProperty(self.CACHE_KEY)
if not cache_json:
logger.debug('Memory cache empty')
logging.debug('Memory cache empty')
return None
try:
cache = json.loads(cache_json)
except ValueError as exc:
logger.debug(f'Memory cache error: {exc}')
logging.debug(f'Memory cache error: {exc}')
return None
if cache['id'] != obj_id or time.time() - cache['timestamp'] > EPISODES_CACHE_TTL:
logger.debug('Memory cache miss')
logging.debug('Memory cache miss')
return None
logger.debug('Memory cache hit')
logging.debug('Memory cache hit')
return cache['object']


Expand Down Expand Up @@ -110,8 +111,8 @@ def load_show_info_from_cache(show_id: Union[int, str]) -> Optional[Dict[str, An
with open(os.path.join(CACHE_DIR, file_name), 'r', encoding='utf-8') as fo:
cache_json = fo.read()
show_info = json.loads(cache_json)
logger.debug('Show info cache hit')
logging.debug('Show info cache hit')
return show_info
except (IOError, EOFError, ValueError) as exc:
logger.debug(f'Cache error: {type(exc)} {exc}')
logging.debug('Cache error: %s %s', type(exc), exc)
return None
12 changes: 6 additions & 6 deletions metadata.tvmaze/libs/data_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

"""Functions to process data"""
import json
import logging
import re
from collections import defaultdict
from typing import Optional, Dict, List, Any, Sequence, NamedTuple
Expand All @@ -26,7 +27,6 @@
from xbmcgui import ListItem

from . import tvmaze_api, cache_service as cache
from .utils import logger

InfoType = Dict[str, Any] # pylint: disable=invalid-name

Expand All @@ -47,7 +47,7 @@
('</i>', '[/I]'),
('</p><p>', '[CR]'),
)
SUPPORTED_EXTERNAL_IDS = ('tvdb', 'imdb')
SUPPORTED_EXTERNAL_IDS = ('tvdb', 'thetvdb', 'imdb')


class UrlParseResult(NamedTuple):
Expand Down Expand Up @@ -116,7 +116,7 @@ def get_episode_info(show_id: str,
key = f'{episode_id}_{season}_{episode}'
episode_info = episodes_map[key]
except KeyError as exc:
logger.error(f'Unable to retrieve episode info: {exc}')
logging.error('Unable to retrieve episode info: %s', exc)
if episode_info is None:
episode_info = tvmaze_api.load_episode_info(episode_id)
return episode_info
Expand Down Expand Up @@ -313,9 +313,9 @@ def parse_url_nfo_contents(nfo: str) -> Optional[UrlParseResult]:
if show_id_match is not None:
provider = show_id_match.group(1)
show_id = show_id_match.group(2)
logger.debug(f'Matched show ID {show_id} by regexp "{regexp}"')
logging.debug('Matched show ID %s by regexp "%s"', show_id, regexp)
return UrlParseResult(provider, show_id)
logger.debug('Unable to find show ID in an NFO file')
logging.debug('Unable to find show ID in an NFO file')
return None


Expand Down Expand Up @@ -403,7 +403,7 @@ def _filter_by_year(shows: List[InfoType], year: str) -> Optional[InfoType]:


def search_show(title: str, year: str) -> Sequence[InfoType]:
logger.debug(f'Searching for TV show {title} ({year})')
logging.debug(f'Searching for TV show %s (%s)', title, year)
raw_search_results = tvmaze_api.search_show(title)
search_results = [res['show'] for res in raw_search_results]
if len(search_results) > 1 and year:
Expand Down
Loading
Loading