# -*- 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