kodi.plugin.video.youtube/resources/lib/youtube_plugin/kodion/items/base_item.py
MoojMidge 36f1cc6048 Misc optimisations
- Avoid using dir()
- Remove custom url quote methods that are no longer faster than urllib.parse methods in newer Python versions
- Reduce polling intervals when checking if Kodi is busy
- Use custom requests.Session class to avoid creation of unused default https adapter and ssl context
2025-11-16 10:50:30 +11:00

388 lines
11 KiB
Python

# -*- coding: utf-8 -*-
"""
Copyright (C) 2014-2016 bromix (plugin.video.youtube)
Copyright (C) 2016-2025 plugin.video.youtube
SPDX-License-Identifier: GPL-2.0-only
See LICENSES/GPL-2.0-only for more information.
"""
from __future__ import absolute_import, division, unicode_literals
import json
from datetime import date, datetime
from .menu_items import separator
from ..compatibility import (
datetime_infolabel,
string_type,
to_str,
unescape,
)
from ..constants import MEDIA_PATH
from ..utils.methods import generate_hash
class BaseItem(object):
_version = 3
_playable = False
def __init__(self, name, uri, image=None, fanart=None, **_kwargs):
super(BaseItem, self).__init__()
self._name = None
self.set_name(name)
self._uri = uri
self._available = True
self._callback = None
self._filter_reason = None
self._special_sort = None
self._image = ''
if image:
self.set_image(image)
self._fanart = ''
if fanart:
self.set_fanart(fanart)
self._bookmark_id = None
self._bookmark_timestamp = None
self._context_menu = None
self._added_utc = None
self._count = None
self._date = None
self._dateadded = None
self._short_details = None
self._production_code = None
self._track_number = None
self._cast = None
self._artists = None
self._studios = None
def __str_parts__(self, as_dict=False):
kwargs = {
'type': self.__class__.__name__,
'name': self._name,
'uri': self._uri,
'available': self._available,
'added': self._added_utc,
'filtered': self._filter_reason,
}
if as_dict:
return kwargs
out = (
'{type}(',
'name={name!r}, ',
'uri={uri!r}, ',
'available={available!r}, ',
'added=\'{added!s}\', ',
'filtered={filtered!r})',
)
return out, kwargs
def __str__(self):
out, kwargs = self.__str_parts__()
return ''.join(out).format(**kwargs)
def __repr_data__(self):
return {'type': self.__class__.__name__, 'data': self.__dict__}
def __repr__(self):
return json.dumps(
self.__repr_data__(),
ensure_ascii=False,
cls=_Encoder
)
@staticmethod
def generate_id(*args, **kwargs):
prefix = kwargs.get('prefix')
if prefix:
return '%s.%s' % (prefix, generate_hash(*args))
return generate_hash(*args)
def get_id(self):
"""
Returns a unique id of the item.
:return: unique id of the item.
"""
return self.generate_id(self._name, self._uri)
def set_name(self, name):
try:
name = unescape(name)
except Exception:
pass
self._name = name
return name
def get_name(self):
"""
Returns the name of the item.
:return: name of the item.
"""
return self._name
def set_uri(self, uri):
self._uri = uri if uri and isinstance(uri, string_type) else ''
def get_uri(self):
"""
Returns the path of the item.
:return: path of the item.
"""
return self._uri
@property
def available(self):
return self._available
@available.setter
def available(self, value):
self._available = value
@property
def callback(self):
return self._callback
@callback.setter
def callback(self, value):
self._callback = value.__get__(self) if callable(value) else None
def set_image(self, image):
if not image:
return
if '{media}/' in image:
self._image = image.format(media=MEDIA_PATH)
else:
self._image = image
def get_image(self):
return self._image
def set_fanart(self, fanart):
if not fanart:
return
if '{media}/' in fanart:
self._fanart = fanart.format(media=MEDIA_PATH)
else:
self._fanart = fanart
def get_fanart(self, default=True):
if self._fanart or not default:
return self._fanart
return '/'.join((
MEDIA_PATH,
'fanart.jpg',
))
def add_context_menu(self,
context_menu,
position='end',
replace=False,
end_separator=separator()):
context_menu = [item for item in context_menu if item]
if context_menu and end_separator and context_menu[-1] != end_separator:
context_menu.append(end_separator)
if replace or not self._context_menu:
self._context_menu = context_menu
elif position == 'end':
self._context_menu.extend(context_menu)
else:
self._context_menu[position:position] = context_menu
def get_context_menu(self):
return self._context_menu
def set_date(self, year, month, day, hour=0, minute=0, second=0):
self._date = datetime(year, month, day, hour, minute, second)
def set_date_from_datetime(self, date_time):
self._date = date_time
def get_date(self, as_text=False, short=False, as_info_label=False):
if self._date:
if as_info_label:
return datetime_infolabel(self._date, '%d.%m.%Y')
if short:
return self._date.date().strftime('%x')
if as_text:
return self._date.strftime('%x %X')
return self._date
def set_dateadded(self, year, month, day, hour=0, minute=0, second=0):
self._dateadded = datetime(year,
month,
day,
hour,
minute,
second)
def set_dateadded_from_datetime(self, date_time):
self._dateadded = date_time
def get_dateadded(self, as_text=False, as_info_label=False):
if self._dateadded:
if as_info_label:
return datetime_infolabel(self._dateadded)
if as_text:
return self._dateadded.strftime('%x %X')
return self._dateadded
def set_added_utc(self, date_time):
self._added_utc = date_time
def get_added_utc(self):
return self._added_utc
def get_short_details(self):
return self._short_details
def set_short_details(self, details):
self._short_details = details or ''
def get_count(self):
return self._count
def set_count(self, count):
self._count = int(count or 0)
@property
def bookmark_id(self):
return self._bookmark_id
@bookmark_id.setter
def bookmark_id(self, value):
self._bookmark_id = value
def set_bookmark_timestamp(self, timestamp):
self._bookmark_timestamp = timestamp
def get_bookmark_timestamp(self):
return self._bookmark_timestamp
@property
def playable(self):
return self._playable
@playable.setter
def playable(self, value):
self._playable = value
def add_artist(self, artist):
if artist:
if self._artists is None:
self._artists = []
self._artists.append(to_str(artist))
def get_artists(self):
return self._artists
def get_artists_string(self):
if self._artists:
return ', '.join(self._artists)
return None
def set_artists(self, artists):
self._artists = list(artists)
def set_cast(self, members):
self._cast = list(members)
def add_cast(self, name, role=None, order=None, thumbnail=None):
if name:
if self._cast is None:
self._cast = []
self._cast.append({
'name': to_str(name),
'role': to_str(role) if role else '',
'order': int(order) if order else len(self._cast) + 1,
'thumbnail': to_str(thumbnail) if thumbnail else '',
})
def get_cast(self):
return self._cast
def add_studio(self, studio):
if studio:
if self._studios is None:
self._studios = []
self._studios.append(to_str(studio))
def get_studios(self):
return self._studios
def set_studios(self, studios):
self._studios = list(studios)
def set_production_code(self, value):
self._production_code = value or ''
def get_production_code(self):
return self._production_code
def set_track_number(self, track_number):
self._track_number = int(track_number)
def get_track_number(self):
return self._track_number
def set_filter_reason(self, reason):
self._filter_reason = reason
def get_filter_reason(self):
return self._filter_reason
def set_special_sort(self, position):
self._special_sort = position
def get_special_sort(self):
return self._special_sort
class _Encoder(json.JSONEncoder):
def encode(self, obj, nested=False):
if isinstance(obj, (date, datetime)):
class_name = obj.__class__.__name__
try:
if obj.fromisoformat:
obj = {
'__class__': class_name,
'__isoformat__': obj.isoformat(),
}
else:
raise AttributeError
except AttributeError:
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'
obj = {
'__class__': class_name,
'__format_string__': format_string,
'__value__': obj.strftime(format_string)
}
if isinstance(obj, string_type):
output = to_str(obj)
elif isinstance(obj, dict):
output = {to_str(key): self.encode(value, nested=True)
for key, value in obj.items()}
elif isinstance(obj, (list, tuple)):
output = [self.encode(item, nested=True) for item in obj]
else:
output = obj
if nested:
return output
return super(_Encoder, self).encode(output)
def default(self, obj):
pass