Skip to content

Commit

Permalink
Merge branch 'feature-no-dependencies' into feature-no-deps-leia
Browse files Browse the repository at this point in the history
  • Loading branch information
pkscout committed Oct 2, 2020
2 parents 89e9010 + 197ce16 commit 63346b9
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 133 deletions.
4 changes: 1 addition & 3 deletions addon.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="metadata.tvshows.themoviedb.org.python"
name="TMDb TV Shows"
version="1.1.13"
version="1.1.14"
provider-name="Team Kodi">
<requires>
<import addon="xbmc.python" version="2.26.0" />
<import addon="xbmc.metadata" version="2.1.0" />
<import addon="script.module.six" version="1.13.0" />
<import addon="script.module.requests" version="2.22.0" />
</requires>
<extension point="xbmc.metadata.scraper.tvshows" library="main.py"/>
<extension point="xbmc.addon.metadata">
Expand Down
19 changes: 8 additions & 11 deletions libs/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@

from __future__ import absolute_import, unicode_literals

import sys
import six
import xbmcgui
import xbmcplugin
from six.moves import urllib_parse
import sys, urllib.parse
import xbmcgui, xbmcplugin
from . import tmdb, data_utils
from .utils import logger, safe_get
try:
Expand All @@ -40,7 +37,7 @@
def find_show(title, year=None):
# type: (Union[Text, bytes], Optional[Text]) -> None
"""Find a show by title"""
if not isinstance(title, six.text_type):
if not isinstance(title, str):
title = title.decode('utf-8')
logger.debug('Searching for TV show {} ({})'.format(title, year))
search_results = tmdb.search_show(title, year)
Expand Down Expand Up @@ -126,13 +123,13 @@ def get_episode_list(show_id): # pylint: disable=missing-docstring
for episode in show_info['episodes']:
list_item = xbmcgui.ListItem(episode['name'], offscreen=True)
list_item = data_utils.add_episode_info(list_item, episode, full_info=False)
encoded_ids = urllib_parse.urlencode(
encoded_ids = urllib.parse.urlencode(
{'show_id': str(show_info['id']), 'episode_id': str(theindex)}
)
theindex = theindex + 1
# Below "url" is some unique ID string (may be an actual URL to an episode page)
# that allows to retrieve information about a specific episode.
url = urllib_parse.quote(encoded_ids)
url = urllib.parse.quote(encoded_ids)
xbmcplugin.addDirectoryItem(
HANDLE,
url=url,
Expand All @@ -143,8 +140,8 @@ def get_episode_list(show_id): # pylint: disable=missing-docstring

def get_episode_details(encoded_ids): # pylint: disable=missing-docstring
# type: (Text) -> None
encoded_ids = urllib_parse.unquote(encoded_ids)
decoded_ids = dict(urllib_parse.parse_qsl(encoded_ids))
encoded_ids = urllib.parse.unquote(encoded_ids)
decoded_ids = dict(urllib.parse.parse_qsl(encoded_ids))
logger.debug('Getting episode details for {}'.format(decoded_ids))
episode_info = tmdb.load_episode_info(
decoded_ids['show_id'], decoded_ids['episode_id']
Expand Down Expand Up @@ -184,7 +181,7 @@ def router(paramstring):
:param paramstring: url-encoded query string
:raises RuntimeError: on unknown call action
"""
params = dict(urllib_parse.parse_qsl(paramstring))
params = dict(urllib.parse.parse_qsl(paramstring))
logger.debug('Called addon with params: {}'.format(sys.argv))
if params['action'] == 'find':
find_show(params['title'], params.get('year'))
Expand Down
50 changes: 30 additions & 20 deletions libs/api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
from __future__ import absolute_import, unicode_literals

import json
from urllib.request import Request, urlopen
from urllib.error import URLError
from urllib.parse import urlencode
from pprint import pformat
import requests
from requests.exceptions import HTTPError
from . import settings
from .utils import logger
try:
Expand All @@ -31,33 +32,42 @@
except ImportError:
pass

HEADERS = (
('User-Agent', 'Kodi scraper for themoviedb.org by pkscout; [email protected]'),
('Accept', 'application/json'),
)
SESSION = requests.Session()
SESSION.headers.update(dict(HEADERS))
HEADERS = {}


def set_headers(headers):
SESSION.headers.update(headers)
HEADERS.update(headers)


def load_info(url, params=None):
def load_info(url, params=None, default=None, resp_type = 'json'):
# type: (Text, Optional[Dict[Text, Union[Text, List[Text]]]]) -> Union[dict, list]
"""
Load info from themoviedb
Load info from external api
:param url: API endpoint URL
:param params: URL query params
:return: API response
:raises requests.exceptions.HTTPError: if any error happens
:default: object to return if there is an error
:resp_type: what to return to the calling function
:return: API response or default on error
"""
logger.debug('Calling URL "{}" with params {}'.format(url, params))
response = SESSION.get(url, params=params)
if not response.ok:
response.raise_for_status()
json_response = response.json()
if params:
url = url + '?' + urlencode(params)
logger.debug('Calling URL "{}"'.format(url))
req = Request(url, headers=HEADERS)
try:
response = urlopen(req)
except URLError as e:
if hasattr(e, 'reason'):
logger.debug('failed to reach the remote site\nReason: {}'.format(e.reason))
elif hasattr(e, 'code'):
logger.debug('remote site unable to fulfill the request\nError code: {}'.format(e.code))
response = None
if response is None:
resp = default
elif resp_type.lower() == 'json':
resp = json.loads(response.read().decode('utf-8'))
else:
resp = response.read().decode('utf-8')
if settings.VERBOSELOG:
logger.debug('the api response:\n{}'.format(pformat(json_response)))
return json_response
logger.debug('the api response:\n{}'.format(pformat(resp)))
return resp
14 changes: 3 additions & 11 deletions libs/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,9 @@

from __future__ import absolute_import, unicode_literals

import os
import os, pickle
from datetime import datetime, timedelta

from six import PY2, PY3
from six.moves import cPickle as pickle
import xbmc
import xbmcvfs
import xbmc, xbmcvfs

from .utils import ADDON, logger

Expand All @@ -44,8 +40,6 @@
def _get_cache_directory(): # pylint: disable=missing-docstring
# type: () -> Text
profile_dir = xbmc.translatePath(ADDON.getAddonInfo('profile'))
if PY2:
profile_dir = profile_dir.decode('utf-8')
cache_dir = os.path.join(profile_dir, 'cache')
if not xbmcvfs.exists(cache_dir):
xbmcvfs.mkdir(cache_dir)
Expand Down Expand Up @@ -81,9 +75,7 @@ def load_show_info_from_cache(show_id):
try:
with open(os.path.join(CACHE_DIR, file_name), 'rb') as fo:
load_kwargs = {}
if PY3:
# https://forum.kodi.tv/showthread.php?tid=349813&pid=2970989#pid2970989
load_kwargs['encoding'] = 'bytes'
load_kwargs['encoding'] = 'bytes'
cache = pickle.load(fo, **load_kwargs)
if datetime.now() - cache['timestamp'] > CACHING_DURATION:
return None
Expand Down
7 changes: 3 additions & 4 deletions libs/data_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import re, json
from collections import OrderedDict, namedtuple
import six
from .utils import safe_get, logger
from . import settings

Expand Down Expand Up @@ -114,7 +113,7 @@ def _set_unique_ids(ext_ids, list_item):
# type: (InfoType, ListItem) -> ListItem
"""Extract unique ID in various online databases"""
unique_ids = {}
for key, value in six.iteritems(ext_ids):
for key, value in ext_ids.items():
if key in VALIDEXTIDS and value:
key = key[:-3]
unique_ids[key] = str(value)
Expand Down Expand Up @@ -146,7 +145,7 @@ def _add_season_info(show_info, list_item):
if image:
url = settings.IMAGEROOTURL + image
list_item.addAvailableArtwork(url, 'poster', season=season['season_number'])
for image_type, image_list in six.iteritems(season.get('images', {})):
for image_type, image_list in season.get('images', {}).items():
if image_type == 'posters':
destination = 'poster'
else:
Expand All @@ -163,7 +162,7 @@ def _add_season_info(show_info, list_item):
def set_show_artwork(show_info, list_item):
# type: (InfoType, ListItem) -> ListItem
"""Set available images for a show"""
for image_type, image_list in six.iteritems(show_info.get('images', {})):
for image_type, image_list in show_info.get('images', {}).items():
if image_type == 'backdrops':
fanart_list = []
for image in image_list:
Expand Down
3 changes: 1 addition & 2 deletions libs/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from platform import uname
from pprint import pformat

import six
import xbmc

from .utils import logger
Expand All @@ -50,7 +49,7 @@ def _format_vars(variables):
:return: formatted string with sorted ``var = val`` pairs
:rtype: str
"""
var_list = [(var, val) for var, val in six.iteritems(variables)
var_list = [(var, val) for var, val in variables.items()
if not (var.startswith('__') or var.endswith('__'))]
var_list.sort(key=lambda i: i[0])
lines = []
Expand Down
19 changes: 4 additions & 15 deletions libs/imdbratings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,22 @@


import re
import requests
from requests.exceptions import ConnectionError as RequestsConnectionError, Timeout, RequestException
from . import api_utils

IMDB_RATINGS_URL = 'https://www.imdb.com/title/{}/'

IMDB_RATING_REGEX = re.compile(r'itemprop="ratingValue".*?>.*?([\d.]+).*?<')
IMDB_VOTES_REGEX = re.compile(r'itemprop="ratingCount".*?>.*?([\d,]+).*?<')

# get the tv show info via imdb

def get_details(imdb_id):
if not imdb_id:
return {}
votes, rating = _get_ratinginfo(imdb_id)
return _assemble_imdb_result(votes, rating)

def _get_ratinginfo(imdb_id):
try:
response = requests.get(IMDB_RATINGS_URL.format(imdb_id))
except (Timeout, RequestsConnectionError, RequestException) as ex:
return _format_error_message(ex)
return _parse_imdb_result(response.text if response and response.status_code == 200 else '')
response = api_utils.load_info(IMDB_RATINGS_URL.format(imdb_id), default = '', resp_type='text')
return _parse_imdb_result(response)

def _assemble_imdb_result(votes, rating):
result = {}
Expand All @@ -64,9 +59,3 @@ def _parse_imdb_votes(input_html):
if (match):
return int(match.group(1).replace(',', ''))
return None

def _format_error_message(ex):
message = type(ex).__name__
if hasattr(ex, 'message'):
message += ": {0}".format(ex.message)
return {'error': message}
7 changes: 3 additions & 4 deletions libs/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# pylint: disable=missing-docstring

import json, six, sys
from six.moves import urllib_parse
import json, sys, urllib.parse
from .utils import logger
from pprint import pformat

Expand All @@ -41,7 +40,7 @@
'seasonthumb': 'seasonlandscape'
}
try:
source_params = dict(urllib_parse.parse_qsl(sys.argv[2]))
source_params = dict(urllib.parse.parse_qsl(sys.argv[2]))
except IndexError:
source_params = {}
source_settings = json.loads(source_params.get('pathSettings', {}))
Expand All @@ -66,5 +65,5 @@
RATING_TYPES.append('tmdb')
FANARTTV_CLIENTKEY = source_settings.get('fanarttv_clientkey', '')
FANARTTV_ART = {}
for fanarttv_type, tmdb_type in six.iteritems(FANARTTV_MAPPING):
for fanarttv_type, tmdb_type in FANARTTV_MAPPING.items():
FANARTTV_ART[tmdb_type] = source_settings.get('enable_fanarttv_%s' % tmdb_type, False)
Loading

0 comments on commit 63346b9

Please sign in to comment.