astrXbian/.install/.kodi/addons/plugin.video.youtube/resources/lib/youtube_plugin/youtube/helper/resource_manager.py

278 lines
9.9 KiB
Python

# -*- coding: utf-8 -*-
"""
Copyright (C) 2014-2016 bromix (plugin.video.youtube)
Copyright (C) 2016-2018 plugin.video.youtube
SPDX-License-Identifier: GPL-2.0-only
See LICENSES/GPL-2.0-only for more information.
"""
from ..youtube_exceptions import YouTubeException
from ...kodion.utils import FunctionCache, DataCache, strip_html_from_text
class ResourceManager(object):
def __init__(self, context, youtube_client):
self._context = context
self._youtube_client = youtube_client
self._channel_data = {}
self._video_data = {}
self._playlist_data = {}
self._enable_channel_fanart = context.get_settings().get_bool('youtube.channel.fanart.show', True)
def clear(self):
self._context.get_function_cache().clear()
self._context.get_data_cache().clear()
def _get_channel_data(self, channel_id):
return self._channel_data.get(channel_id, {})
def _get_video_data(self, video_id):
return self._video_data.get(video_id, {})
def _get_playlist_data(self, playlist_id):
return self._playlist_data.get(playlist_id, {})
def _update_channels(self, channel_ids):
result = dict()
json_data = dict()
channel_ids_to_update = list()
channel_ids_cached = list()
updated_channel_ids = list()
data_cache = self._context.get_data_cache()
function_cache = self._context.get_function_cache()
for channel_id in channel_ids:
if channel_id == 'mine':
json_data = function_cache.get(FunctionCache.ONE_DAY, self._youtube_client.get_channel_by_username, channel_id)
items = json_data.get('items', [{'id': 'mine'}])
try:
channel_id = items[0]['id']
except IndexError:
self._context.log_debug('Channel "mine" not found: %s' % json_data)
channel_id = None
json_data = dict()
if channel_id:
updated_channel_ids.append(channel_id)
channel_ids = updated_channel_ids
channel_data = data_cache.get_items(DataCache.ONE_MONTH, channel_ids)
for channel_id in channel_ids:
if not channel_data.get(channel_id):
channel_ids_to_update.append(channel_id)
else:
channel_ids_cached.append(channel_id)
result.update(channel_data)
if len(channel_ids_cached) > 0:
self._context.log_debug('Found cached data for channels |%s|' % ', '.join(channel_ids_cached))
if len(channel_ids_to_update) > 0:
self._context.log_debug('No data for channels |%s| cached' % ', '.join(channel_ids_to_update))
data = []
list_of_50s = self._make_list_of_50(channel_ids_to_update)
for list_of_50 in list_of_50s:
data.append(self._youtube_client.get_channels(list_of_50))
channel_data = dict()
yt_items = []
for response in data:
yt_items += response.get('items', [])
for yt_item in yt_items:
channel_id = str(yt_item['id'])
channel_data[channel_id] = yt_item
result[channel_id] = yt_item
data_cache.set_all(channel_data)
self._context.log_debug('Cached data for channels |%s|' % ', '.join(list(channel_data.keys())))
if self.handle_error(json_data):
return result
return result
def _update_videos(self, video_ids, live_details=False, suppress_errors=False):
result = dict()
json_data = dict()
video_ids_to_update = list()
video_ids_cached = list()
data_cache = self._context.get_data_cache()
video_data = data_cache.get_items(DataCache.ONE_MONTH, video_ids)
for video_id in video_ids:
if not video_data.get(video_id):
video_ids_to_update.append(video_id)
else:
video_ids_cached.append(video_id)
result.update(video_data)
if len(video_ids_cached) > 0:
self._context.log_debug('Found cached data for videos |%s|' % ', '.join(video_ids_cached))
if len(video_ids_to_update) > 0:
self._context.log_debug('No data for videos |%s| cached' % ', '.join(video_ids_to_update))
json_data = self._youtube_client.get_videos(video_ids_to_update, live_details)
video_data = dict()
yt_items = json_data.get('items', [])
for yt_item in yt_items:
video_id = str(yt_item['id'])
video_data[video_id] = yt_item
result[video_id] = yt_item
data_cache.set_all(video_data)
self._context.log_debug('Cached data for videos |%s|' % ', '.join(list(video_data.keys())))
played_items = dict()
if self._context.get_settings().use_playback_history():
playback_history = self._context.get_playback_history()
played_items = playback_history.get_items(video_ids)
for k in list(result.keys()):
result[k]['play_data'] = played_items.get(k, dict())
if self.handle_error(json_data, suppress_errors) or suppress_errors:
return result
@staticmethod
def _make_list_of_50(list_of_ids):
list_of_50 = []
pos = 0
while pos < len(list_of_ids):
list_of_50.append(list_of_ids[pos:pos + 50])
pos += 50
return list_of_50
def get_videos(self, video_ids, live_details=False, suppress_errors=False):
list_of_50s = self._make_list_of_50(video_ids)
result = {}
for list_of_50 in list_of_50s:
result.update(self._update_videos(list_of_50, live_details, suppress_errors))
return result
def _update_playlists(self, playlists_ids):
result = dict()
json_data = dict()
playlist_ids_to_update = list()
playlists_ids_cached = list()
data_cache = self._context.get_data_cache()
playlist_data = data_cache.get_items(DataCache.ONE_MONTH, playlists_ids)
for playlist_id in playlists_ids:
if not playlist_data.get(playlist_id):
playlist_ids_to_update.append(playlist_id)
else:
playlists_ids_cached.append(playlist_id)
result.update(playlist_data)
if len(playlists_ids_cached) > 0:
self._context.log_debug('Found cached data for playlists |%s|' % ', '.join(playlists_ids_cached))
if len(playlist_ids_to_update) > 0:
self._context.log_debug('No data for playlists |%s| cached' % ', '.join(playlist_ids_to_update))
json_data = self._youtube_client.get_playlists(playlist_ids_to_update)
playlist_data = dict()
yt_items = json_data.get('items', [])
for yt_item in yt_items:
playlist_id = str(yt_item['id'])
playlist_data[playlist_id] = yt_item
result[playlist_id] = yt_item
data_cache.set_all(playlist_data)
self._context.log_debug('Cached data for playlists |%s|' % ', '.join(list(playlist_data.keys())))
if self.handle_error(json_data):
return result
def get_playlists(self, playlists_ids):
list_of_50s = self._make_list_of_50(playlists_ids)
result = {}
for list_of_50 in list_of_50s:
result.update(self._update_playlists(list_of_50))
return result
def get_related_playlists(self, channel_id):
result = self._update_channels([channel_id])
# transform
item = None
if channel_id != 'mine':
item = result.get(channel_id, {})
else:
for key in list(result.keys()):
item = result[key]
if item is None:
return {}
return item.get('contentDetails', {}).get('relatedPlaylists', {})
def get_channels(self, channel_ids):
list_of_50s = self._make_list_of_50(channel_ids)
result = {}
for list_of_50 in list_of_50s:
result.update(self._update_channels(list_of_50))
return result
def get_fanarts(self, channel_ids):
if not self._enable_channel_fanart:
return {}
result = self._update_channels(channel_ids)
# transform
for key in list(result.keys()):
item = result[key]
# set an empty url
result[key] = u''
images = item.get('brandingSettings', {}).get('image', {})
banners = ['bannerTvMediumImageUrl', 'bannerTvLowImageUrl', 'bannerTvImageUrl']
for banner in banners:
image = images.get(banner, '')
if image:
result[key] = image
break
return result
def handle_error(self, json_data, suppress_errors=False):
context = self._context
if json_data and 'error' in json_data:
ok_dialog = False
message_timeout = 5000
message = json_data['error'].get('message', '')
message = strip_html_from_text(message)
reason = json_data['error']['errors'][0].get('reason', '')
title = '%s: %s' % (context.get_name(), reason)
error_message = 'Error reason: |%s| with message: |%s|' % (reason, message)
context.log_error(error_message)
if reason == 'accessNotConfigured':
message = context.localize(30731)
ok_dialog = True
if reason == 'quotaExceeded' or reason == 'dailyLimitExceeded':
message_timeout = 7000
if not suppress_errors:
if ok_dialog:
context.get_ui().on_ok(title, message)
else:
context.get_ui().show_notification(message, title,
time_milliseconds=message_timeout)
raise YouTubeException(error_message)
return False
return True