remove future and dateutil dependency

This commit is contained in:
warwickh 2021-09-28 09:05:01 +10:00
parent f97b9e1de9
commit 7baa12f06f
3 changed files with 34 additions and 73 deletions

View File

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.audio.subsonic" name="Subsonic" version="3.0.1" provider-name="BasilFX,grosbouff,silascutler,Heruwar,warwickh"> <addon id="plugin.audio.subsonic" name="Subsonic" version="3.0.1" provider-name="BasilFX,warwickh">
<requires> <requires>
<import addon="xbmc.python" version="3.0.0"/> <import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.4.2"/>
<import addon="script.module.future" version="0.18.2"/>
</requires> </requires>
<extension point="xbmc.python.pluginsource" library="main.py"> <extension point="xbmc.python.pluginsource" library="main.py">
<provides>audio</provides> <provides>audio</provides>

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Created on: 03.06.2015 # Created on: 03.06.2015
# Python2 support removed 28.09.2021
""" """
SimplePlugin micro-framework for Kodi content plugins SimplePlugin micro-framework for Kodi content plugins
@ -8,17 +9,8 @@ SimplePlugin micro-framework for Kodi content plugins
**License**: `GPL v.3 <https://www.gnu.org/copyleft/gpl.html>`_ **License**: `GPL v.3 <https://www.gnu.org/copyleft/gpl.html>`_
""" """
from __future__ import unicode_literals basestring = str
from future.builtins import (zip, super, long = int
bytes, dict, int, list, object, str)
from future.utils import (PY2, PY3, iteritems, itervalues,
python_2_unicode_compatible)
# from future.standard_library import install_aliases
# install_aliases()
if PY3:
basestring = str
long = int
import os import os
import sys import sys
@ -34,24 +26,16 @@ from shutil import copyfile
from contextlib import contextmanager from contextlib import contextmanager
from pprint import pformat from pprint import pformat
from platform import uname from platform import uname
if PY3: from urllib.parse import urlencode, quote_plus, urlparse, unquote_plus, parse_qs
from urllib.parse import urlencode, quote_plus, urlparse, unquote_plus, parse_qs
else:
from future.backports.urllib.parse import urlencode, quote_plus, urlparse, unquote_plus
from urlparse import parse_qs
import xbmcaddon import xbmcaddon
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
__all__ = ['SimplePluginError', 'Storage', 'MemStorage', 'Addon', 'Plugin', __all__ = ['SimplePluginError', 'Storage', 'MemStorage', 'Addon', 'Plugin',
'RoutedPlugin', 'Params', 'log_exception', 'py2_encode', 'RoutedPlugin', 'Params', 'log_exception', 'translate_path']
'py2_decode', 'translate_path']
if PY3: getargspec = inspect.getfullargspec
getargspec = inspect.getfullargspec
else:
getargspec = inspect.getargspec
Route = namedtuple('Route', ['pattern', 'func']) Route = namedtuple('Route', ['pattern', 'func'])
@ -81,28 +65,6 @@ def _format_vars(variables):
lines.append('{0} = {1}'.format(var, pformat(val))) lines.append('{0} = {1}'.format(var, pformat(val)))
return '\n'.join(lines) return '\n'.join(lines)
def py2_encode(s, encoding='utf-8'):
"""
Encode Python 2 ``unicode`` to ``str``
In Python 3 the string is not changed.
"""
if PY2 and isinstance(s, str):
s = s.encode(encoding)
return s
def py2_decode(s, encoding='utf-8'):
"""
Decode Python 2 ``str`` to ``unicode``
In Python 3 the string is not changed.
"""
if PY2 and isinstance(s, bytes):
s = s.decode(encoding)
return s
def _kodi_major_version(): def _kodi_major_version():
kodi_version = xbmc.getInfoLabel('System.BuildVersion').split(' ')[0] kodi_version = xbmc.getInfoLabel('System.BuildVersion').split(' ')[0]
return kodi_version.split('.')[0] return kodi_version.split('.')[0]
@ -146,12 +108,12 @@ def log_exception(logger=None):
yield yield
except: except:
if logger is None: if logger is None:
logger = lambda msg: xbmc.log(py2_encode(msg), xbmc.LOGERROR) logger = lambda msg: xbmc.log(msg, xbmc.LOGERROR)
frame_info = inspect.trace(5)[-1] frame_info = inspect.trace(5)[-1]
logger('Unhandled exception detected!') logger('Unhandled exception detected!')
logger('*** Start diagnostic info ***') logger('*** Start diagnostic info ***')
logger('System info: {0}'.format(uname())) logger('System info: {0}'.format(uname()))
logger('OS info: {0}'.format(py2_decode(xbmc.getInfoLabel('System.OSVersionInfo')))) logger('OS info: {0}'.format(xbmc.getInfoLabel('System.OSVersionInfo')))
logger('Kodi version: {0}'.format( logger('Kodi version: {0}'.format(
xbmc.getInfoLabel('System.BuildVersion')) xbmc.getInfoLabel('System.BuildVersion'))
) )
@ -170,7 +132,7 @@ def log_exception(logger=None):
raise raise
@python_2_unicode_compatible
class Params(dict): class Params(dict):
""" """
Params(**kwargs) Params(**kwargs)
@ -198,7 +160,7 @@ class Params(dict):
return '<Params {0}>'.format(super(Params, self).__str__()) return '<Params {0}>'.format(super(Params, self).__str__())
@python_2_unicode_compatible
class Storage(MutableMapping): class Storage(MutableMapping):
""" """
Storage(storage_dir, filename='storage.pcl') Storage(storage_dir, filename='storage.pcl')
@ -303,7 +265,7 @@ class Storage(MutableMapping):
return deepcopy(self._storage) return deepcopy(self._storage)
@python_2_unicode_compatible
class MemStorage(MutableMapping): class MemStorage(MutableMapping):
""" """
MemStorage(storage_id) MemStorage(storage_id)
@ -367,7 +329,7 @@ class MemStorage(MutableMapping):
def __getitem__(self, key): def __getitem__(self, key):
self._check_key(key) self._check_key(key)
full_key = py2_encode('{0}__{1}'.format(self._id, key)) full_key = '{0}__{1}'.format(self._id, key)
raw_item = self._window.getProperty(full_key) raw_item = self._window.getProperty(full_key)
if raw_item: if raw_item:
try: try:
@ -379,7 +341,7 @@ class MemStorage(MutableMapping):
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._check_key(key) self._check_key(key)
full_key = py2_encode('{0}__{1}'.format(self._id, key)) full_key = '{0}__{1}'.format(self._id, key)
# protocol=0 is needed for safe string handling in Python 3 # protocol=0 is needed for safe string handling in Python 3
self._window.setProperty(full_key, pickle.dumps(value, protocol=0)) self._window.setProperty(full_key, pickle.dumps(value, protocol=0))
if key != '__keys__': if key != '__keys__':
@ -389,7 +351,7 @@ class MemStorage(MutableMapping):
def __delitem__(self, key): def __delitem__(self, key):
self._check_key(key) self._check_key(key)
full_key = py2_encode('{0}__{1}'.format(self._id, key)) full_key = '{0}__{1}'.format(self._id, key)
item = self._window.getProperty(full_key) item = self._window.getProperty(full_key)
if item: if item:
self._window.clearProperty(full_key) self._window.clearProperty(full_key)
@ -402,7 +364,7 @@ class MemStorage(MutableMapping):
def __contains__(self, key): def __contains__(self, key):
self._check_key(key) self._check_key(key)
full_key = py2_encode('{0}__{1}'.format(self._id, key)) full_key = '{0}__{1}'.format(self._id, key)
item = self._window.getProperty(full_key) item = self._window.getProperty(full_key)
return bool(item) return bool(item)
@ -413,7 +375,7 @@ class MemStorage(MutableMapping):
return len(self['__keys__']) return len(self['__keys__'])
@python_2_unicode_compatible
class Addon(object): class Addon(object):
""" """
Base addon class Base addon class
@ -430,9 +392,7 @@ class Addon(object):
:type id_: str :type id_: str
""" """
self._addon = xbmcaddon.Addon(id_) self._addon = xbmcaddon.Addon(id_)
self._profile_dir = py2_decode( self._profile_dir = translate_path(self._addon.getAddonInfo('profile'))
translate_path(self._addon.getAddonInfo('profile'))
)
self._ui_strings_map = None self._ui_strings_map = None
if not os.path.exists(self._profile_dir): if not os.path.exists(self._profile_dir):
os.mkdir(self._profile_dir) os.mkdir(self._profile_dir)
@ -468,7 +428,7 @@ class Addon(object):
:return: path to the addon folder :return: path to the addon folder
:rtype: unicode :rtype: unicode
""" """
return py2_decode(self._addon.getAddonInfo('path')) return self._addon.getAddonInfo('path')
@property @property
def icon(self): def icon(self):
@ -633,7 +593,7 @@ class Addon(object):
:type convert: bool :type convert: bool
:return: setting value :return: setting value
""" """
setting = py2_decode(self._addon.getSetting(id_)) setting = self._addon.getSetting(id_)
if convert: if convert:
if setting == 'true': if setting == 'true':
return True # Convert boolean strings to bool return True # Convert boolean strings to bool
@ -664,7 +624,7 @@ class Addon(object):
value = 'true' if value else 'false' value = 'true' if value else 'false'
elif not isinstance(value, basestring): elif not isinstance(value, basestring):
value = str(value) value = str(value)
self._addon.setSetting(id_, py2_encode(value)) self._addon.setSetting(id_, value)
def log(self, message, level=xbmc.LOGDEBUG): def log(self, message, level=xbmc.LOGDEBUG):
""" """
@ -677,7 +637,7 @@ class Addon(object):
:type level: int :type level: int
""" """
xbmc.log( xbmc.log(
py2_encode('{0} [v.{1}]: {2}'.format(self.id, self.version, message)), '{0} [v.{1}]: {2}'.format(self.id, self.version, message),
level level
) )
@ -957,7 +917,7 @@ class Addon(object):
return ui_strings return ui_strings
@python_2_unicode_compatible
class Plugin(Addon): class Plugin(Addon):
""" """
Plugin class with URL query string routing. Plugin class with URL query string routing.
@ -1016,9 +976,9 @@ class Plugin(Addon):
""" """
raw_params = parse_qs(paramstring) raw_params = parse_qs(paramstring)
params = Params() params = Params()
for key, value in iteritems(raw_params): for key, value in iter(raw_params.items()):
param_value = value[0] if len(value) == 1 else value param_value = value[0] if len(value) == 1 else value
params[key] = py2_decode(param_value) params[key] = param_value
return params return params
def get_url(self, plugin_url='', **kwargs): def get_url(self, plugin_url='', **kwargs):
@ -1125,7 +1085,7 @@ class Plugin(Addon):
return action_callable(self._params) return action_callable(self._params)
@python_2_unicode_compatible
class RoutedPlugin(Plugin): class RoutedPlugin(Plugin):
""" """
Plugin class that implements "pretty URL" routing similar to Flask and Bottle Plugin class that implements "pretty URL" routing similar to Flask and Bottle
@ -1224,7 +1184,7 @@ class RoutedPlugin(Plugin):
for arg, match in zip(args, matches): for arg, match in zip(args, matches):
pattern = pattern.replace( pattern = pattern.replace(
match, match,
quote_plus(py2_encode(str(arg))) quote_plus(str(arg))
) )
# list allows to manipulate the dict during iteration # list allows to manipulate the dict during iteration
for key, value in list(iteritems(kwargs)): for key, value in list(iteritems(kwargs)):
@ -1237,7 +1197,7 @@ class RoutedPlugin(Plugin):
if key == match_string: if key == match_string:
pattern = pattern.replace( pattern = pattern.replace(
match, quote_plus(py2_encode(str(value))) match, quote_plus(str(value))
) )
del kwargs[key] del kwargs[key]
url = 'plugin://{0}{1}'.format(self.id, pattern) url = 'plugin://{0}{1}'.format(self.id, pattern)
@ -1378,7 +1338,7 @@ class RoutedPlugin(Plugin):
value = float(value) value = float(value)
kwargs[key] = value kwargs[key] = value
else: else:
kwargs[key] = py2_decode(unquote_plus(value)) kwargs[key] = unquote_plus(value)
self.log_debug( self.log_debug(
'Calling {0} with kwargs {1}'.format(route, kwargs)) 'Calling {0} with kwargs {1}'.format(route, kwargs))
with log_exception(self.log_error): with log_exception(self.log_error):

View File

@ -9,7 +9,6 @@ import xbmcgui
import json import json
import shutil import shutil
import time import time
import dateutil.parser
import hashlib import hashlib
import random import random
from datetime import datetime from datetime import datetime
@ -1052,7 +1051,11 @@ def navigate_root():
#converts a date string from eg. '2012-04-17T19:53:44' to eg. '17.04.2012' #converts a date string from eg. '2012-04-17T19:53:44' to eg. '17.04.2012'
def convert_date_from_iso8601(iso8601): def convert_date_from_iso8601(iso8601):
date_obj = dateutil.parser.parse(iso8601) format = "%Y-%m-%dT%H:%M:%S"
try:
date_obj = datetime.strptime(iso8601.split(".")[0], format)
except TypeError:
date_obj = datetime(*(time.strptime(iso8601.split(".")[0], format)[0:6]))
return date_obj.strftime('%d.%m.%Y') return date_obj.strftime('%d.%m.%Y')
def context_action_star(type,id): def context_action_star(type,id):