Python2 unicode fixes #668

This commit is contained in:
MoojMidge 2024-04-01 06:44:51 +11:00
parent 516ca89696
commit 49df1d5eb3
6 changed files with 80 additions and 60 deletions

View file

@ -15,6 +15,7 @@ __all__ = (
'parse_qsl',
'quote',
'string_type',
'to_str',
'unescape',
'unquote',
'urlencode',
@ -52,6 +53,7 @@ try:
string_type = str
byte_string_type = bytes
to_str = str
# Compatibility shims for Kodi v18 and Python v2.7
except ImportError:
import BaseHTTPServer
@ -79,23 +81,21 @@ except ImportError:
def quote(data, *args, **kwargs):
return _quote(data.encode('utf-8'), *args, **kwargs)
return _quote(to_str(data), *args, **kwargs)
def unquote(data):
return _unquote(data.encode('utf-8'))
return _unquote(to_str(data))
def urlencode(data, *args, **kwargs):
if isinstance(data, dict):
data = data.items()
return _urlencode({
key.encode('utf-8'): (
[part.encode('utf-8') if isinstance(part, unicode)
else str(part)
for part in value] if isinstance(value, (list, tuple))
else value.encode('utf-8') if isinstance(value, unicode)
else str(value)
to_str(key): (
[to_str(part) for part in value]
if isinstance(value, (list, tuple)) else
to_str(value)
)
for key, value in data
}, *args, **kwargs)
@ -121,6 +121,11 @@ except ImportError:
string_type = basestring
byte_string_type = (bytes, str)
def to_str(value):
if isinstance(value, unicode):
return value.encode('utf-8')
return str(value)
# Kodi v20+
if hasattr(xbmcgui.ListItem, 'setDateTime'):
def datetime_infolabel(datetime_obj):

View file

@ -13,7 +13,7 @@ from __future__ import absolute_import, division, unicode_literals
import os
from .. import logger
from ..compatibility import urlencode
from ..compatibility import to_str, urlencode
from ..json_store import AccessManager
from ..sql_store import (
DataCache,
@ -265,7 +265,7 @@ class AbstractContext(object):
val for val in value.split(',') if val
]
elif param in self._STRING_PARAMS:
parsed_value = str(value)
parsed_value = to_str(value)
# process and translate deprecated parameters
if param == 'action':
if parsed_value in ('play_all', 'play_video'):

View file

@ -11,7 +11,7 @@
from __future__ import absolute_import, division, unicode_literals
from .base_item import BaseItem
from ..compatibility import unescape
from ..compatibility import to_str, unescape
class AudioItem(BaseItem):
@ -54,7 +54,7 @@ class AudioItem(BaseItem):
if self._artists is None:
self._artists = []
if artist:
self._artists.append(str(artist))
self._artists.append(to_str(artist))
def get_artists(self):
return self._artists
@ -72,7 +72,7 @@ class AudioItem(BaseItem):
if self._genres is None:
self._genres = []
if genre:
self._genres.append(str(genre))
self._genres.append(to_str(genre))
def get_genres(self):
return self._genres

View file

@ -14,13 +14,12 @@ import json
from datetime import date, datetime
from hashlib import md5
from ..compatibility import datetime_infolabel, string_type, unescape
from ..compatibility import datetime_infolabel, string_type, to_str, unescape
from ..constants import MEDIA_PATH
class BaseItem(object):
VERSION = 3
INFO_DATE = 'date' # (string) iso 8601
_playable = False
@ -48,43 +47,19 @@ class BaseItem(object):
self._next_page = False
def __str__(self):
name = self._name
uri = self._uri
image = self._image
obj_str = "------------------------------\n'%s'\nURI: %s\nImage: %s\n------------------------------" % (name, uri, image)
return obj_str
return ('------------------------------\n'
'Name: |{0}|\n'
'URI: |{1}|\n'
'Image: |{2}|\n'
'------------------------------'.format(self._name,
self._uri,
self._image))
def to_dict(self):
return {'type': self.__class__.__name__, 'data': self.__dict__}
def dumps(self):
def _encoder(obj):
if isinstance(obj, (date, datetime)):
class_name = obj.__class__.__name__
if 'fromisoformat' in dir(obj):
return {
'__class__': class_name,
'__isoformat__': obj.isoformat(),
}
if class_name == 'datetime':
if obj.tzinfo:
format_string = '%Y-%m-%dT%H:%M:%S%z'
else:
format_string = '%Y-%m-%dT%H:%M:%S'
else:
format_string = '%Y-%m-%d'
return {
'__class__': class_name,
'__format_string__': format_string,
'__value__': obj.strftime(format_string)
}
return json.JSONEncoder().default(obj)
return json.dumps(self.to_dict(), ensure_ascii=False, default=_encoder)
return json.dumps(self.to_dict(), ensure_ascii=False, cls=_Encoder)
def get_id(self):
"""
@ -230,5 +205,43 @@ class BaseItem(object):
self._next_page = bool(value)
@property
def playable(cls):
return cls._playable
def playable(self):
return self._playable
class _Encoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, string_type):
return to_str(obj)
if isinstance(obj, dict):
return {to_str(key): self.encode(value)
for key, value in obj.items()}
if isinstance(obj, (list, tuple)):
return [self.encode(item) for item in obj]
if isinstance(obj, (date, datetime)):
class_name = obj.__class__.__name__
if 'fromisoformat' in dir(obj):
return {
'__class__': class_name,
'__isoformat__': obj.isoformat(),
}
if class_name == 'datetime':
if obj.tzinfo:
format_string = '%Y-%m-%dT%H:%M:%S%z'
else:
format_string = '%Y-%m-%dT%H:%M:%S'
else:
format_string = '%Y-%m-%d'
return {
'__class__': class_name,
'__format_string__': format_string,
'__value__': obj.strftime(format_string)
}
return self.iterencode(obj)

View file

@ -14,7 +14,7 @@ import datetime
import re
from .base_item import BaseItem
from ..compatibility import datetime_infolabel, unescape
from ..compatibility import datetime_infolabel, to_str, unescape
from ..utils import duration_to_seconds, seconds_to_duration
@ -71,7 +71,7 @@ class VideoItem(BaseItem):
if self._artists is None:
self._artists = []
if artist:
self._artists.append(str(artist))
self._artists.append(to_str(artist))
def get_artists(self):
return self._artists
@ -83,7 +83,7 @@ class VideoItem(BaseItem):
if self._studios is None:
self._studios = []
if studio:
self._studios.append(str(studio))
self._studios.append(to_str(studio))
def get_studios(self):
return self._studios
@ -156,7 +156,7 @@ class VideoItem(BaseItem):
if self._directors is None:
self._directors = []
if director:
self._directors.append(str(director))
self._directors.append(to_str(director))
def get_directors(self):
return self._directors
@ -169,10 +169,10 @@ class VideoItem(BaseItem):
self._cast = []
if member:
self._cast.append({
'member': str(member),
'role': str(role) if role else '',
'member': to_str(member),
'role': to_str(role) if role else '',
'order': int(order) if order else len(self._cast) + 1,
'thumbnail': str(thumbnail) if thumbnail else '',
'thumbnail': to_str(thumbnail) if thumbnail else '',
})
def get_cast(self):
@ -262,7 +262,7 @@ class VideoItem(BaseItem):
if self._genres is None:
self._genres = []
if genre:
self._genres.append(str(genre))
self._genres.append(to_str(genre))
def get_genres(self):
return self._genres

View file

@ -20,7 +20,7 @@ from random import randint
from .login_client import LoginClient
from ..helper.video_info import VideoInfo
from ..youtube_exceptions import InvalidJSON, YouTubeException
from ...kodion.compatibility import string_type
from ...kodion.compatibility import string_type, to_str
from ...kodion.utils import (
current_system_version,
datetime_parser,
@ -1542,13 +1542,15 @@ class YouTube(LoginClient):
for thread in threads:
thread.join(30)
do_encode = not current_system_version.compatible(19, 0)
for response in responses:
if response:
response.encoding = 'utf-8'
xml_data = to_unicode(response.content)
xml_data = xml_data.replace('\n', '')
if not current_system_version.compatible(19, 0):
xml_data = xml_data.encode('utf-8')
if do_encode:
xml_data = to_str(xml_data)
root = ET.fromstring(xml_data)