mirror of
https://github.com/anxdpanic/plugin.video.youtube.git
synced 2025-12-06 02:30:50 -08:00
- 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
388 lines
11 KiB
Python
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
|