278 lines
9.9 KiB
Python
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
|