261 lines
9.3 KiB
Python
261 lines
9.3 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.
|
|
"""
|
|
|
|
import json
|
|
import random
|
|
import re
|
|
import traceback
|
|
|
|
import xbmcplugin
|
|
|
|
from ... import kodion
|
|
from ...kodion import constants
|
|
from ...kodion.items import VideoItem
|
|
from ...kodion.impl.xbmc.xbmc_items import to_playback_item
|
|
from ...youtube.youtube_exceptions import YouTubeException
|
|
from ...youtube.helper import utils, v3
|
|
|
|
|
|
def play_video(provider, context):
|
|
try:
|
|
video_id = context.get_param('video_id')
|
|
|
|
client = provider.get_client(context)
|
|
settings = context.get_settings()
|
|
|
|
ask_for_quality = None
|
|
if video_id and context.get_ui().get_home_window_property('ask_for_quality') == video_id:
|
|
ask_for_quality = True
|
|
context.get_ui().clear_home_window_property('ask_for_quality')
|
|
|
|
screensaver = False
|
|
if context.get_param('screensaver', None) and str(context.get_param('screensaver')).lower() == 'true':
|
|
ask_for_quality = False
|
|
screensaver = True
|
|
|
|
audio_only = None
|
|
if video_id and context.get_ui().get_home_window_property('audio_only') == video_id:
|
|
ask_for_quality = False
|
|
audio_only = True
|
|
context.get_ui().clear_home_window_property('audio_only')
|
|
|
|
try:
|
|
video_streams = client.get_video_streams(context, video_id)
|
|
except YouTubeException as e:
|
|
context.get_ui().show_notification(message=e.get_message())
|
|
context.log_error(traceback.print_exc())
|
|
return False
|
|
|
|
if len(video_streams) == 0:
|
|
message = context.localize(provider.LOCAL_MAP['youtube.error.no_video_streams_found'])
|
|
context.get_ui().show_notification(message, time_milliseconds=5000)
|
|
return False
|
|
|
|
video_stream = kodion.utils.select_stream(context, video_streams, ask_for_quality=ask_for_quality, audio_only=audio_only)
|
|
|
|
if video_stream is None:
|
|
return False
|
|
|
|
is_video = True if video_stream.get('video') else False
|
|
is_live = video_stream.get('Live') is True
|
|
|
|
if is_video and video_stream['video'].get('rtmpe', False):
|
|
message = context.localize(provider.LOCAL_MAP['youtube.error.rtmpe_not_supported'])
|
|
context.get_ui().show_notification(message, time_milliseconds=5000)
|
|
return False
|
|
|
|
play_suggested = settings.get_bool('youtube.suggested_videos', False)
|
|
if play_suggested and not screensaver:
|
|
utils.add_related_video_to_playlist(provider, context, client, v3, video_id)
|
|
|
|
metadata = video_stream.get('meta', {})
|
|
|
|
title = metadata.get('video', {}).get('title', '')
|
|
video_item = VideoItem(title, video_stream['url'])
|
|
|
|
incognito = str(context.get_param('incognito', False)).lower() == 'true'
|
|
use_history = not is_live and not screensaver and not incognito
|
|
playback_history = use_history and settings.use_playback_history()
|
|
|
|
video_item = utils.update_play_info(provider, context, video_id, video_item, video_stream,
|
|
use_play_data=playback_history)
|
|
|
|
seek_time = None
|
|
play_count = 0
|
|
playback_stats = video_stream.get('playback_stats')
|
|
|
|
if use_history:
|
|
major_version = context.get_system_version().get_version()[0]
|
|
if video_item.get_start_time() and video_item.use_dash() and major_version > 17:
|
|
seek_time = video_item.get_start_time()
|
|
play_count = video_item.get_play_count() if video_item.get_play_count() is not None else '0'
|
|
|
|
item = to_playback_item(context, video_item)
|
|
item.setPath(video_item.get_uri())
|
|
|
|
try:
|
|
seek = float(context.get_param('seek', None))
|
|
if seek:
|
|
seek_time = seek
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
playback_json = {
|
|
"video_id": video_id,
|
|
"channel_id": metadata.get('channel', {}).get('id', ''),
|
|
"video_status": metadata.get('video', {}).get('status', {}),
|
|
"playing_file": video_item.get_uri(),
|
|
"play_count": play_count,
|
|
"use_history": use_history,
|
|
"playback_history": playback_history,
|
|
"playback_stats": playback_stats,
|
|
"seek_time": seek_time,
|
|
"refresh_only": screensaver
|
|
}
|
|
|
|
context.get_ui().set_home_window_property('playback_json', json.dumps(playback_json))
|
|
context.send_notification('PlaybackInit', {
|
|
'video_id': video_id,
|
|
'channel_id': playback_json.get('channel_id', ''),
|
|
'status': playback_json.get('video_status', {})
|
|
})
|
|
xbmcplugin.setResolvedUrl(handle=context.get_handle(), succeeded=True, listitem=item)
|
|
|
|
except YouTubeException as ex:
|
|
message = ex.get_message()
|
|
message = kodion.utils.strip_html_from_text(message)
|
|
context.get_ui().show_notification(message, time_milliseconds=15000)
|
|
|
|
|
|
def play_playlist(provider, context):
|
|
videos = []
|
|
|
|
def _load_videos(_page_token='', _progress_dialog=None):
|
|
if _progress_dialog is None:
|
|
_progress_dialog = context.get_ui().create_progress_dialog(
|
|
context.localize(provider.LOCAL_MAP['youtube.playlist.progress.updating']),
|
|
context.localize(constants.localize.COMMON_PLEASE_WAIT), background=True)
|
|
json_data = client.get_playlist_items(playlist_id, page_token=_page_token)
|
|
if not v3.handle_error(provider, context, json_data):
|
|
return None
|
|
_progress_dialog.set_total(int(json_data.get('pageInfo', {}).get('totalResults', 0)))
|
|
|
|
result = v3.response_to_items(provider, context, json_data, process_next_page=False)
|
|
videos.extend(result)
|
|
progress_text = '%s %d/%d' % (
|
|
context.localize(constants.localize.COMMON_PLEASE_WAIT), len(videos), _progress_dialog.get_total())
|
|
_progress_dialog.update(steps=len(result), text=progress_text)
|
|
|
|
next_page_token = json_data.get('nextPageToken', '')
|
|
if next_page_token:
|
|
_load_videos(_page_token=next_page_token, _progress_dialog=_progress_dialog)
|
|
|
|
return _progress_dialog
|
|
|
|
# select order
|
|
video_id = context.get_param('video_id', '')
|
|
order = context.get_param('order', '')
|
|
if not order:
|
|
order_list = ['default', 'reverse']
|
|
# we support shuffle only without a starting video position
|
|
if not video_id:
|
|
order_list.append('shuffle')
|
|
items = []
|
|
for order in order_list:
|
|
items.append((context.localize(provider.LOCAL_MAP['youtube.playlist.play.%s' % order]), order))
|
|
|
|
order = context.get_ui().on_select(context.localize(provider.LOCAL_MAP['youtube.playlist.play.select']), items)
|
|
if order not in order_list:
|
|
return False
|
|
|
|
player = context.get_video_player()
|
|
player.stop()
|
|
|
|
playlist_id = context.get_param('playlist_id')
|
|
client = provider.get_client(context)
|
|
|
|
# start the loop and fill the list with video items
|
|
progress_dialog = _load_videos()
|
|
|
|
# reverse the list
|
|
if order == 'reverse':
|
|
videos = videos[::-1]
|
|
elif order == 'shuffle':
|
|
# we have to shuffle the playlist by our self. The implementation of XBMC/KODI is quite weak :(
|
|
random.shuffle(videos)
|
|
|
|
playlist_position = 0
|
|
# check if we have a video as starting point for the playlist
|
|
if video_id:
|
|
find_video_id = re.compile(r'video_id=(?P<video_id>[^&]+)')
|
|
for video in videos:
|
|
video_id_match = find_video_id.search(video.get_uri())
|
|
if video_id_match and video_id_match.group('video_id') == video_id:
|
|
break
|
|
playlist_position += 1
|
|
|
|
# clear the playlist
|
|
playlist = context.get_video_playlist()
|
|
playlist.clear()
|
|
|
|
# select unshuffle
|
|
if order == 'shuffle':
|
|
playlist.unshuffle()
|
|
|
|
# add videos to playlist
|
|
for video in videos:
|
|
playlist.add(video)
|
|
|
|
# we use the shuffle implementation of the playlist
|
|
"""
|
|
if order == 'shuffle':
|
|
playlist.shuffle()
|
|
"""
|
|
|
|
if progress_dialog:
|
|
progress_dialog.close()
|
|
|
|
if (context.get_param('play', '') == '1') and (context.get_handle() == -1):
|
|
player.play(playlist_index=playlist_position)
|
|
return
|
|
elif context.get_param('play', '') == '1':
|
|
return videos[playlist_position]
|
|
|
|
return True
|
|
|
|
|
|
def play_channel_live(provider, context):
|
|
channel_id = context.get_param('channel_id')
|
|
index = int(context.get_param('live')) - 1
|
|
if index < 0:
|
|
index = 0
|
|
json_data = provider.get_client(context).search(q='', search_type='video', event_type='live', channel_id=channel_id, safe_search=False)
|
|
if not v3.handle_error(provider, context, json_data):
|
|
return False
|
|
|
|
video_items = v3.response_to_items(provider, context, json_data, process_next_page=False)
|
|
|
|
try:
|
|
video_item = video_items[index]
|
|
except IndexError:
|
|
return False
|
|
|
|
player = context.get_video_player()
|
|
player.stop()
|
|
|
|
playlist = context.get_video_playlist()
|
|
playlist.clear()
|
|
playlist.add(video_item)
|
|
|
|
if context.get_handle() == -1:
|
|
player.play(playlist_index=0)
|
|
else:
|
|
return video_item
|