Add manual transcode option

Update queue playlist
This commit is contained in:
angelblue05 2018-09-09 00:44:23 -05:00
parent cdb3b54026
commit 24ab27bbe2
8 changed files with 212 additions and 46 deletions

View file

@ -418,6 +418,14 @@ msgctxt "#33009"
msgid "Invalid username or password"
msgstr ""
msgctxt "#33013"
msgid "Choose the audio stream"
msgstr ""
msgctxt "#33014"
msgid "Choose the subtitles stream"
msgstr ""
msgctxt "#33015"
msgid "Delete file from Emby?"
msgstr ""
@ -757,3 +765,15 @@ msgstr ""
msgctxt "#33156"
msgid "A patch has been applied!"
msgstr ""
msgctxt "#33157"
msgid "Audio only"
msgstr ""
msgctxt "#33158"
msgid "Subtitles only"
msgstr ""
msgctxt "#33159"
msgid "Enable audio/subtitles selection"
msgstr ""

View file

@ -172,6 +172,9 @@ def delete_item(item_id):
def get_local_trailers(item_id):
return user_items("/%s/LocalTrailers" % item_id)
def get_transcode_settings():
return _get('System/Configuration/encoding')
def get_ancestors(item_id):
return items("/%s/Ancestors" % item_id, params={
'UserId': "{UserId}"

View file

@ -69,7 +69,7 @@ class Events(object):
elif mode =='play':
item = TheVoid('GetItem', {'Id': params['id'], 'ServerId': server}).get()
Actions(params.get('server')).play(item, params.get('dbid'))
Actions(params.get('server')).play(item, params.get('dbid'), playlist=params.get('playlist') == 'true')
elif mode == 'playlist':
event('PlayPlaylist', {'Id': params['id'], 'ServerId': server})

View file

@ -13,6 +13,7 @@ import xbmcvfs
import api
import database
import client
import collections
from . import _, settings, window, dialog
from libraries import requests
from downloader import TheVoid
@ -102,7 +103,7 @@ class PlayUtils(object):
return sources
def select_source(self, sources):
def select_source(self, sources, audio=None, subtitle=None):
if len(sources) > 1:
selection = []
@ -119,7 +120,7 @@ class PlayUtils(object):
else:
source = sources[0]
self.get(source)
self.get(source, audio, subtitle)
return source
@ -171,7 +172,7 @@ class PlayUtils(object):
return False
def get(self, source):
def get(self, source, audio=None, subtitle=None):
''' The server returns sources based on the MaxStreamingBitrate value and other filters.
'''
@ -192,10 +193,10 @@ class PlayUtils(object):
else:
LOG.info("--[ transcode ]")
self.transcode(source)
self.transcode(source, audio, subtitle)
self.info['AudioStreamIndex'] = source.get('DefaultAudioStreamIndex')
self.info['SubtitleStreamIndex'] = source.get('DefaultSubtitleStreamIndex')
self.info['AudioStreamIndex'] = self.info.get('AudioStreamIndex') or source.get('DefaultAudioStreamIndex')
self.info['SubtitleStreamIndex'] = self.info.get('SubtitleStreamIndex') or source.get('DefaultSubtitleStreamIndex')
self.item['PlaybackInfo'].update(self.info)
def live_stream(self, source):
@ -217,13 +218,23 @@ class PlayUtils(object):
return info['MediaSource']
def transcode(self, source):
def transcode(self, source, audio=None, subtitle=None):
if not 'TranscodingUrl' in source:
raise Exception("use get_sources to get transcoding url")
self.info['Method'] = "Transcode"
base, params = source['TranscodingUrl'].split('?')
if settings('skipDialogTranscode') != "3" and source.get('MediaStreams'):
url_parsed = params.split('&')
for i in url_parsed:
if 'AudioStreamIndex' in i or 'AudioBitrate' in i or 'SubtitleStreamIndex' in i: # handle manually
url_parsed.remove(i)
params = "%s%s" % ('&'.join(url_parsed), self.get_audio_subs(source, audio, subtitle))
self.info['Path'] = "%s/emby%s?%s" % (self.info['ServerAddress'], base.replace('stream', "master"), params)
self.info['Path'] += "&maxWidth=%s&maxHeight=%s" % (self.get_resolution())
@ -422,8 +433,7 @@ class PlayUtils(object):
if 'DeliveryUrl' in stream:
url = "%s/emby%s" % (self.info['ServerAddress'], stream['DeliveryUrl'])
else:
url = ("%s/emby/Videos/%s/%s/Subtitles/%s/Stream.%s?api_key=%s" %
(self.info['ServerAddress'], self.item['Id'], source['Id'], index, stream['Codec'], self.info['Token']))
url = self.get_subtitles(source, stream, index)
if url is None:
continue
@ -462,7 +472,7 @@ class PlayUtils(object):
path = os.path.join(temp, filename)
try:
response = requests.get(src, stream=True)
response = requests.get(src, stream=True, verify=False)
response.raise_for_status()
except Exception as e:
raise
@ -473,3 +483,113 @@ class PlayUtils(object):
del response
return path
def get_audio_subs(self, source, audio=None, subtitle=None):
''' For transcoding only
Present the list of audio/subs to select from, before playback starts.
Since Emby returns all possible tracks together, sort them.
IsTextSubtitleStream if true, is available to download from server.
'''
prefs = ""
audio_streams = collections.OrderedDict()
subs_streams = collections.OrderedDict()
streams = source['MediaStreams']
for stream in streams:
index = stream['Index']
stream_type = stream['Type']
if stream_type == 'Audio':
codec = stream['Codec']
channel = stream.get('ChannelLayout', "")
if 'Language' in stream:
track = "%s - %s - %s %s" % (index, stream['Language'], codec, channel)
else:
track = "%s - %s %s" % (index, codec, channel)
audio_streams[track] = index
elif stream_type == 'Subtitle':
if 'Language' in stream:
track = "%s - %s" % (index, stream['Language'])
else:
track = "%s - %s" % (index, stream['Codec'])
if stream['IsDefault']:
track = "%s - Default" % track
if stream['IsForced']:
track = "%s - Forced" % track
subs_streams[track] = index
skip_dialog = int(settings('skipDialogTranscode') or 0)
audio_selected = None
if audio:
audio_selected = audio
elif skip_dialog in (0, 1):
if len(audio_streams) > 1:
selection = list(audio_streams.keys())
resp = dialog("select", _(33013), selection)
audio_selected = audio_streams[selection[resp]] if resp else source['DefaultAudioStreamIndex']
else: # Only one choice
audio_selected = audio_streams[next(iter(audio_streams))]
else:
audio_selected = source['DefaultAudioStreamIndex']
self.info['AudioStreamIndex'] = audio_selected
prefs += "&AudioStreamIndex=%s" % audio_selected
prefs += "&AudioBitrate=384000" if streams[audio_selected].get('Channels', 0) > 2 else "&AudioBitrate=192000"
if subtitle:
index = subtitle
server_settings = TheVoid('GetTranscodeOptions', {'ServerId': self.info['ServerId']}).get()
stream = streams[index]
if server_settings['EnableSubtitleExtraction'] and stream['SupportsExternalStream']:
self.info['SubtitleUrl'] = self.get_subtitles(source, stream, index)
else:
prefs += "&SubtitleStreamIndex=%s" % index
self.info['SubtitleStreamIndex'] = index
elif skip_dialog in (0, 2) and len(subs_streams):
selection = list(['No subtitles']) + list(subs_streams.keys())
resp = dialog("select", _(33014), selection)
if resp:
index = subs_streams[selection[resp]] if resp > -1 else source.get('DefaultSubtitleStreamIndex')
if index is not None:
server_settings = TheVoid('GetTranscodeOptions', {'ServerId': self.info['ServerId']}).get()
stream = streams[index]
if server_settings['EnableSubtitleExtraction'] and stream['SupportsExternalStream']:
self.info['SubtitleUrl'] = self.get_subtitles(source, stream, index)
else:
prefs += "&SubtitleStreamIndex=%s" % index
self.info['SubtitleStreamIndex'] = index
return prefs
def get_subtitles(self, source, stream, index):
if 'DeliveryUrl' in stream:
url = "%s/emby%s" % (self.info['ServerAddress'], stream['DeliveryUrl'])
else:
url = ("%s/emby/Videos/%s/%s/Subtitles/%s/Stream.%s?api_key=%s" %
(self.info['ServerAddress'], self.item['Id'], source['Id'], index, stream['Codec'], self.info['Token']))
return url

View file

@ -55,7 +55,7 @@ class Monitor(xbmc.Monitor):
'GetServerAddress', 'GetPlaybackInfo', 'Browse', 'GetImages', 'GetToken',
'PlayPlaylist', 'Play', 'GetIntros', 'GetAdditionalParts', 'RefreshItem',
'FavoriteItem', 'DeleteItem', 'AddUser', 'GetSession', 'GetUsers', 'GetThemes',
'GetTheme', 'Playstate', 'GeneralCommand'):
'GetTheme', 'Playstate', 'GeneralCommand', 'GetTranscodeOptions'):
return
data = json.loads(data)[0]
@ -139,6 +139,12 @@ class Monitor(xbmc.Monitor):
window('emby_%s.json' % data['VoidName'], users)
LOG.debug("--->[ beacon/emby_%s.json ] sent", data['VoidName'])
elif method == 'GetTranscodeOptions':
result = server['api'].get_transcode_settings()
window('emby_%s.json' % data['VoidName'], result)
LOG.debug("--->[ beacon/emby_%s.json ] sent", data['VoidName'])
elif method == 'GetThemes':
if data['Type'] == 'Video':
@ -183,8 +189,10 @@ class Monitor(xbmc.Monitor):
elif method == 'Play':
items = server['api'].get_items(data['ItemIds'])
PlaylistWorker(data.get('ServerId'), items['Items'], data['PlayCommand'] == 'PlayNow',
item = server['api'].get_item(data['ItemIds'].pop(0))
data['ItemIds'].insert(0, item)
PlaylistWorker(data.get('ServerId'), data['ItemIds'], data['PlayCommand'] == 'PlayNow',
data.get('StartPositionTicks', 0), data.get('AudioStreamIndex'),
data.get('SubtitleStreamIndex')).start()

View file

@ -43,7 +43,7 @@ class Actions(object):
return xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
def play(self, item, db_id=None, transcode=False):
def play(self, item, db_id=None, transcode=False, playlist=False):
''' Play item based on if playback started from widget ot not.
To get everything to work together, play the first item in the stack with setResolvedUrl,
@ -63,7 +63,7 @@ class Actions(object):
self.stack[0][1].setPath(self.stack[0][0])
try:
if self.detect_widgets(item):
if not playlist and self.detect_widgets(item):
LOG.info(" [ play/widget ]")
raise IndexError
@ -172,10 +172,10 @@ class Actions(object):
def play_playlist(self, items, clear=True, seektime=None, audio=None, subtitle=None):
''' Play a list of items. Creates a new playlist.
''' Play a list of items. Creates a new playlist. Add additional items as plugin listing.
'''
playlist = self.get_playlist(items[0])
started = False
item = items[0]
playlist = self.get_playlist(item)
if clear:
playlist.clear()
@ -183,32 +183,35 @@ class Actions(object):
else:
index = max(playlist.getposition(), 0) + 1 # Can return -1
for order, item in enumerate(items):
listitem = xbmcgui.ListItem()
LOG.info("[ playlist/%s ] %s", item['Id'], item['Name'])
play = playutils.PlayUtils(item, False, self.server_id, self.server)
source = play.select_source(play.get_sources())
play.set_external_subs(source, listitem)
item['PlaybackInfo']['AudioStreamIndex'] = audio or item['PlaybackInfo']['AudioStreamIndex']
item['PlaybackInfo']['SubtitleStreamIndex'] = subtitle or item['PlaybackInfo'].get('SubtitleStreamIndex')
self.set_listitem(item, listitem, None, True if seektime else False)
listitem.setPath(item['PlaybackInfo']['Path'])
playutils.set_properties(item, item['PlaybackInfo']['Method'], self.server_id)
playlist.add(item['PlaybackInfo']['Path'], listitem, index)
index += 1
if clear:
xbmc.Player().play(playlist)
for item in items[1:]:
listitem = xbmcgui.ListItem()
LOG.info("[ playlist/%s ] %s", item['Id'], item['Name'])
LOG.info("[ playlist/%s ]", item)
path = "plugin://plugin.video.emby/?mode=play&id=%s&playlist=true" % item
play = playutils.PlayUtils(item, False, self.server_id, self.server)
source = play.select_source(play.get_sources())
play.set_external_subs(source, listitem)
if order == 0: # First item
item['PlaybackInfo']['AudioStreamIndex'] = audio or item['PlaybackInfo']['AudioStreamIndex']
item['PlaybackInfo']['SubtitleStreamIndex'] = subtitle or item['PlaybackInfo'].get('SubtitleStreamIndex')
self.set_listitem(item, listitem, None, True if order == 0 and seektime else False)
listitem.setPath(item['PlaybackInfo']['Path'])
playutils.set_properties(item, item['PlaybackInfo']['Method'], self.server_id)
playlist.add(item['PlaybackInfo']['Path'], listitem, index)
listitem.setPath(path)
playlist.add(path, listitem, index)
index += 1
if not started and clear:
started = True
xbmc.Player().play(playlist)
def set_listitem(self, item, listitem, db_id=None, seektime=None, intro=False):
objects = Objects()
@ -237,8 +240,15 @@ class Actions(object):
self.listitem_video(obj, listitem, item, seektime)
if 'PlaybackInfo' in item and seektime:
item['PlaybackInfo']['CurrentPosition'] = obj['Resume']
if 'PlaybackInfo' in item:
if seektime:
item['PlaybackInfo']['CurrentPosition'] = obj['Resume']
if 'SubtitleUrl' in item['PlaybackInfo']:
LOG.info("[ subtitles ] %s", item['PlaybackInfo']['SubtitleUrl'])
listitem.setSubtitles([item['PlaybackInfo']['SubtitleUrl']])
listitem.setContentLookup(False)

View file

@ -254,9 +254,14 @@ class Player(xbmc.Player):
''' Report playback progress to emby server.
Check if the user seek.
'''
current_file = self.getPlayingFile()
try:
current_file = self.getPlayingFile()
if current_file not in self.played:
return
except Exception as error:
LOG.error(error)
if current_file not in self.played:
return
item = self.played[current_file]
@ -366,7 +371,7 @@ class Player(xbmc.Player):
elif item['PlayMethod'] == 'Transcode':
LOG.info("Transcoding for %s terminated.", item['Id'])
LOG.info("<[ transcode/%s ]", item['Id'])
item['Server']['api'].close_transcode(item['DeviceId'])

View file

@ -41,7 +41,7 @@
<setting label="30522" id="transcode_h265" type="bool" default="false" />
<setting label="30537" id="transcodeHi10P" type="bool" default="false"/>
<setting label="33114" id="enableExternalSubs" type="bool" default="true" />
<setting label="33159" id="skipDialogTranscode" type="enum" lvalues="305|33157|33158|13106" visible="true" default="3" />
<setting label="33115" type="lsep" />
<setting label="30160" id="videoBitrate" type="enum" values="664 Kbps SD|996 Kbps HD|1.3 Mbps HD|2.0 Mbps HD|3.2 Mbps HD|4.7 Mbps HD|6.2 Mbps HD|7.7 Mbps HD|9.2 Mbps HD|10.7 Mbps HD|12.2 Mbps HD|13.7 Mbps HD|15.2 Mbps HD|16.7 Mbps HD|18.2 Mbps HD|20.0 Mbps HD|25.0 Mbps HD|30.0 Mbps HD|35.0 Mbps HD|40.0 Mbps HD|100.0 Mbps HD [default]|1000.0 Mbps HD" visible="true" default="20" />