Support up next

This commit is contained in:
angelblue05 2018-10-15 06:26:11 -05:00
parent 5808c449c4
commit c3fbdf082c
5 changed files with 110 additions and 18 deletions

View file

@ -159,6 +159,13 @@ def get_next(index=None, limit=1):
'StartIndex': None if index is None else int(index) 'StartIndex': None if index is None else int(index)
}) })
def get_adjacent_episodes(show_id, item_id):
return shows("/%s/Episodes" % show_id, {
'UserId': "{UserId}",
'AdjacentTo': item_id,
'Fields': "Overview"
})
def get_genres(parent_id=None): def get_genres(parent_id=None):
return _get("Genres", { return _get("Genres", {
'ParentId': parent_id, 'ParentId': parent_id,

View file

@ -46,7 +46,8 @@ def set_properties(item, method, server_id=None):
'SubsMapping': info.get('Subtitles'), 'SubsMapping': info.get('Subtitles'),
'AudioStreamIndex': info.get('AudioStreamIndex'), 'AudioStreamIndex': info.get('AudioStreamIndex'),
'SubtitleStreamIndex': info.get('SubtitleStreamIndex'), 'SubtitleStreamIndex': info.get('SubtitleStreamIndex'),
'CurrentPosition': info.get('CurrentPosition') 'CurrentPosition': info.get('CurrentPosition'),
'CurrentEpisode': info.get('CurrentEpisode')
}) })
window('emby_play.json', current) window('emby_play.json', current)
@ -400,6 +401,14 @@ class PlayUtils(object):
} }
if settings('transcode_h265.bool'): if settings('transcode_h265.bool'):
profile['DirectPlayProfiles'][0]['VideoCodec'] = "h264,mpeg4,mpeg2video" profile['DirectPlayProfiles'][0]['VideoCodec'] = "h264,mpeg4,mpeg2video"
else:
profile['TranscodingProfiles'].insert(0, {
"Container": "m3u8",
"Type": "Video",
"AudioCodec": "aac,mp3,ac3,opus,flac,vorbis",
"VideoCodec": "h264,h265,hevc,mpeg4,mpeg2video",
"MaxAudioChannels": "6"
})
if settings('transcodeHi10P.bool'): if settings('transcodeHi10P.bool'):
profile['CodecProfiles'].append( profile['CodecProfiles'].append(

View file

@ -2,6 +2,7 @@
################################################################################################# #################################################################################################
import binascii
import json import json
import logging import logging
import os import os
@ -127,13 +128,20 @@ def find(dict, item):
if re.match(key, item, re.I): if re.match(key, item, re.I):
return dict[key] return dict[key]
def event(method, data=None): def event(method, data=None, sender=None, hexlify=False):
''' Data is a dictionary. ''' Data is a dictionary.
''' '''
data = data or {} data = data or {}
xbmc.executebuiltin('NotifyAll(plugin.video.emby, %s, "[%s]")' % (method, json.dumps(data).replace('"', '\\"'))) sender = sender or "plugin.video.emby"
LOG.debug("---[ event: %s ] %s", method, data)
if hexlify:
data = '\\"[\\"{0}\\"]\\"'.format(binascii.hexlify(json.dumps(data)))
else:
data = '"[%s]"' % json.dumps(data).replace('"', '\\"')
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
LOG.debug("---[ event: %s/%s ] %s", sender, method, data)
def dialog(dialog_type, *args, **kwargs): def dialog(dialog_type, *args, **kwargs):

View file

@ -2,6 +2,7 @@
################################################################################################# #################################################################################################
import binascii
import json import json
import logging import logging
import threading import threading
@ -46,7 +47,7 @@ class Monitor(xbmc.Monitor):
def onNotification(self, sender, method, data): def onNotification(self, sender, method, data):
if sender.lower() not in ('plugin.video.emby', 'xbmc'): if sender.lower() not in ('plugin.video.emby', 'xbmc', 'upnextprovider'):
return return
if sender == 'plugin.video.emby': if sender == 'plugin.video.emby':
@ -61,6 +62,18 @@ class Monitor(xbmc.Monitor):
return return
data = json.loads(data)[0] data = json.loads(data)[0]
elif sender == 'upnextprovider':
method = method.split('.')[1]
if method not in ('plugin.video.emby_play_action'):
return
data = json.loads(data)
method = "Play"
if data:
data = json.loads(binascii.unhexlify(data[0]))
else: else:
if method not in ('Player.OnPlay', 'VideoLibrary.OnUpdate', 'Player.OnAVChange'): if method not in ('Player.OnPlay', 'VideoLibrary.OnUpdate', 'Player.OnAVChange'):
return return

View file

@ -9,7 +9,8 @@ import os
import xbmc import xbmc
import xbmcvfs import xbmcvfs
from helper import _, window, settings, dialog, JSONRPC from objects.obj import Objects
from helper import _, api, window, settings, dialog, event, JSONRPC
from emby import Emby from emby import Emby
################################################################################################# #################################################################################################
@ -24,6 +25,7 @@ class Player(xbmc.Player):
# Borg - multiple instances, shared state # Borg - multiple instances, shared state
_shared_state = {} _shared_state = {}
played = {} played = {}
up_next = False
def __init__(self): def __init__(self):
@ -35,6 +37,7 @@ class Player(xbmc.Player):
''' We may need to wait for info to be set in kodi monitor. ''' We may need to wait for info to be set in kodi monitor.
Accounts for scenario where Kodi starts playback and exits immediately. Accounts for scenario where Kodi starts playback and exits immediately.
''' '''
self.up_next = False
count = 0 count = 0
monitor = xbmc.Monitor() monitor = xbmc.Monitor()
@ -219,6 +222,49 @@ class Player(xbmc.Player):
else: else:
item['SubtitleStreamIndex'] = subs + tracks + 1 item['SubtitleStreamIndex'] = subs + tracks + 1
def next_up(self):
current_file = self.getPlayingFile()
item = self.played[current_file]
objects = Objects()
if item['Type'] != 'Episode':
return
next_items = item['Server']['api'].get_adjacent_episodes(item['CurrentEpisode']['tvshowid'], item['Id'])
for index, next_item in enumerate(next_items['Items']):
if next_item['Id'] == item['Id']:
try:
next_item = next_items['Items'][index + 1]
except IndexError:
LOG.warn("No next up episode.")
return
break
API = api.API(next_item, item['Server']['auth/server-address'])
data = objects.map(next_item, "UpNext")
artwork = API.get_all_artwork(objects.map(next_item, 'ArtworkParent'), True)
data['art'] = {
'tvshow.poster': artwork.get('Series.Primary'),
'tvshow.fanart': None,
'thumb': artwork.get('Primary')
}
if artwork['Backdrop']:
data['art']['tvshow.fanart'] = artwork['Backdrop'][0]
next_info = {
'play_info': {'ItemIds': [data['episodeid']], 'ServerId': item['ServerId'], 'PlayCommand': 'PlayNow'},
'current_episode': item['CurrentEpisode'],
'next_episode': data
}
LOG.debug("--[ next up ] %s", json.dumps(next_info, indent=4))
event("upnext_data", next_info, hexlify=True)
def onPlayBackPaused(self): def onPlayBackPaused(self):
current_file = self.getPlayingFile() current_file = self.getPlayingFile()
@ -268,15 +314,32 @@ class Player(xbmc.Player):
item = self.played[current_file] item = self.played[current_file]
if window('emby.external.bool'):
return
if not report: if not report:
previous = item['CurrentPosition'] previous = item['CurrentPosition']
item['CurrentPosition'] = int(self.getTime()) item['CurrentPosition'] = int(self.getTime())
if int(item['CurrentPosition']) == 1:
return
try:
played = float(item['CurrentPosition'] * 10000000) / int(item['Runtime']) * 100
except ZeroDivisionError: # Runtime is 0.
played = 0
if played > 2.0 and not self.up_next:
self.up_next = True
self.next_up()
if (item['CurrentPosition'] - previous) < 30: if (item['CurrentPosition'] - previous) < 30:
return return
result = JSONRPC('Application.GetProperties').execute({'properties': ["volume", "muted"]}) result = JSONRPC('Application.GetProperties').execute({'properties': ["volume", "muted"]})
result = result.get('result', {}) result = result.get('result', {})
item['Volume'] = result.get('volume') item['Volume'] = result.get('volume')
@ -330,18 +393,10 @@ class Player(xbmc.Player):
if item: if item:
window('emby.skip.%s.bool' % item['Id'], True) window('emby.skip.%s.bool' % item['Id'], True)
if item['CurrentPosition'] and item['Runtime']:
try:
if window('emby.external.bool'): if window('emby.external.bool'):
window('emby.external', clear=True) window('emby.external', clear=True)
raise ValueError
played = float(item['CurrentPosition'] * 10000000) / int(item['Runtime']) if int(item['CurrentPosition']) == 1:
except ZeroDivisionError: # Runtime is 0.
played = 0
except ValueError:
played = 100
item['CurrentPosition'] = int(item['Runtime']) item['CurrentPosition'] = int(item['Runtime'])
data = { data = {