jellyfin-kodi/resources/lib/playbackutils.py

331 lines
11 KiB
Python
Raw Normal View History

2016-03-31 15:58:49 +00:00
# -*- coding: utf-8 -*-
#################################################################################################
import json
import logging
2016-10-28 05:02:47 +00:00
import requests
import os
import shutil
2016-03-31 15:58:49 +00:00
import sys
import xbmc
import xbmcgui
import xbmcplugin
2016-10-28 05:02:47 +00:00
import xbmcvfs
2016-03-31 15:58:49 +00:00
import api
import artwork
import downloadutils
import playutils as putils
import playlist
import read_embyserver as embyserver
import shutil
import embydb_functions as embydb
from database import DatabaseConn
from utils import window, settings, language as lang
#################################################################################################
log = logging.getLogger("EMBY."+__name__)
2016-03-31 15:58:49 +00:00
#################################################################################################
class PlaybackUtils(object):
2016-03-31 15:58:49 +00:00
def __init__(self, item=None, item_id=None):
2016-03-31 15:58:49 +00:00
self.artwork = artwork.Artwork()
self.emby = embyserver.Read_EmbyServer()
self.item = item or self.emby.getItem(item_id)
self.API = api.API(self.item)
2016-03-31 15:58:49 +00:00
self.server = window('emby_server%s' % window('emby_currUser'))
2016-03-31 15:58:49 +00:00
self.stack = []
2016-03-31 15:58:49 +00:00
if self.item['Type'] == "Audio":
self.playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
else:
self.playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
2016-03-31 15:58:49 +00:00
def play(self, item_id, dbid=None, force_transcode=False):
2016-03-31 15:58:49 +00:00
listitem = xbmcgui.ListItem()
2016-10-28 05:02:47 +00:00
log.info("Play called: %s", self.item['Name'])
2016-03-31 15:58:49 +00:00
resume = window('emby.resume')
window('emby.resume', clear=True)
2016-03-31 15:58:49 +00:00
play_url = putils.PlayUtils(self.item, listitem).get_play_url(force_transcode)
2016-03-31 15:58:49 +00:00
if not play_url:
if play_url == False: # User backed-out of menu
self.playlist.clear()
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
2016-03-31 15:58:49 +00:00
seektime = 0 if resume == "true" else self.API.adjust_resume(self.API.get_userdata()['Resume'])
2016-03-31 15:58:49 +00:00
if force_transcode:
log.info("Clear the playlist.")
self.playlist.clear()
2016-03-31 15:58:49 +00:00
self.set_playlist(play_url, item_id, listitem, seektime, dbid)
2016-03-31 15:58:49 +00:00
##### SETUP PLAYBACK
2016-03-31 15:58:49 +00:00
''' To get everything to work together, play the first item in the stack with setResolvedUrl,
add the rest to the regular playlist.
'''
2016-03-31 15:58:49 +00:00
index = max(self.playlist.getposition(), 0) + 1 # Can return -1
force_play = False
2016-03-31 15:58:49 +00:00
# Stack: [(url, listitem), (url, ...), ...]
self.stack[0][1].setPath(self.stack[0][0])
try:
2018-01-10 01:31:14 +00:00
if (not xbmc.getCondVisibility('Window.IsVisible(MyVideoNav.xml)') and
not xbmc.getCondVisibility('Window.IsVisible(VideoFullScreen.xml)')):
# widgets do not fill artwork correctly
log.info("Detected widget.")
raise IndexError
2016-03-31 15:58:49 +00:00
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, self.stack[0][1])
self.stack.pop(0) # remove the first item we just started.
except IndexError:
log.info("Playback activated via the context menu or widgets.")
force_play = True
self.stack[0][1].setProperty('StartOffset', str(seektime))
2016-03-31 15:58:49 +00:00
for stack in self.stack:
self.playlist.add(url=stack[0], listitem=stack[1], index=index)
index += 1
2016-03-31 15:58:49 +00:00
if force_play:
xbmc.Player().play(self.playlist)
2016-03-31 15:58:49 +00:00
def set_playlist(self, play_url, item_id, listitem, seektime=None, db_id=None):
2016-03-31 15:58:49 +00:00
##### CHECK FOR INTROS
2016-03-31 15:58:49 +00:00
if settings('enableCinema') == "true" and not seektime:
self._set_intros(item_id)
2016-03-31 15:58:49 +00:00
##### ADD MAIN ITEM
2016-03-31 15:58:49 +00:00
self.set_properties(play_url, listitem)
self.set_listitem(listitem, db_id)
self.stack.append([play_url, listitem])
2016-03-31 15:58:49 +00:00
##### ADD ADDITIONAL PARTS
2016-03-31 15:58:49 +00:00
if self.item.get('PartCount'):
self._set_additional_parts(item_id)
2016-03-31 15:58:49 +00:00
def _set_intros(self, item_id):
# if we have any play them when the movie/show is not being resumed
intros = self.emby.get_intros(item_id)
2016-03-31 15:58:49 +00:00
if intros['Items']:
enabled = True
2016-03-31 15:58:49 +00:00
if settings('askCinema') == "true":
2016-03-31 15:58:49 +00:00
resp = xbmcgui.Dialog().yesno("Emby for Kodi", lang(33016))
if not resp:
# User selected to not play trailers
enabled = False
log.info("Skip trailers.")
2016-03-31 15:58:49 +00:00
if enabled:
for intro in intros['Items']:
2016-10-28 05:02:47 +00:00
listitem = xbmcgui.ListItem()
url = putils.PlayUtils(intro, listitem).get_play_url()
log.info("Adding Intro: %s" % url)
2016-10-28 05:02:47 +00:00
self.stack.append([url, listitem])
2016-10-28 05:02:47 +00:00
def _set_additional_parts(self, item_id):
2016-10-28 05:02:47 +00:00
parts = self.emby.get_additional_parts(item_id)
2016-10-28 05:02:47 +00:00
for part in parts['Items']:
2016-03-31 15:58:49 +00:00
listitem = xbmcgui.ListItem()
url = putils.PlayUtils(part, listitem).get_play_url()
log.info("Adding additional part: %s" % url)
2016-03-31 15:58:49 +00:00
# Set listitem and properties for each additional parts
pb = PlaybackUtils(part)
pb.set_properties(url, listitem)
pb.setArtwork(listitem)
self.stack.append([url, listitem])
2016-03-31 15:58:49 +00:00
def set_listitem(self, listitem, dbid=None):
2016-03-31 15:58:49 +00:00
2016-10-28 05:02:47 +00:00
people = self.API.get_people()
mediatype = self.item['Type']
2016-03-31 15:58:49 +00:00
metadata = {
2016-03-31 16:30:52 +00:00
'title': self.item.get('Name', "Missing name"),
'year': self.item.get('ProductionYear'),
2016-10-28 05:02:47 +00:00
'plot': self.API.get_overview(),
2016-03-31 15:58:49 +00:00
'director': people.get('Director'),
'writer': people.get('Writer'),
2016-10-28 05:02:47 +00:00
'mpaa': self.API.get_mpaa(),
2016-03-31 16:30:52 +00:00
'genre': " / ".join(self.item['Genres']),
'studio': " / ".join(self.API.get_studios()),
2016-10-28 05:02:47 +00:00
'aired': self.API.get_premiere_date(),
2016-03-31 16:30:52 +00:00
'rating': self.item.get('CommunityRating'),
'votes': self.item.get('VoteCount')
2016-03-31 15:58:49 +00:00
}
if mediatype == "Episode":
2016-03-31 15:58:49 +00:00
# Only for tv shows
2016-10-28 05:02:47 +00:00
metadata['mediatype'] = "episode"
metadata['TVShowTitle'] = self.item.get('SeriesName', "")
metadata['season'] = self.item.get('ParentIndexNumber', -1)
metadata['episode'] = self.item.get('IndexNumber', -1)
elif mediatype == "Movie":
metadata['mediatype'] = "movie"
2016-10-28 05:02:47 +00:00
elif mediatype == "MusicVideo":
metadata['mediatype'] = "musicvideo"
2016-03-31 15:58:49 +00:00
elif mediatype == "Audio":
metadata['mediatype'] = "song"
2016-03-31 15:58:49 +00:00
if dbid:
2016-10-28 05:02:47 +00:00
metadata['dbid'] = dbid
listitem.setProperty('IsPlayable', 'true')
listitem.setProperty('IsFolder', 'false')
listitem.setLabel(metadata['title'])
listitem.setInfo('Music' if mediatype == "Audio" else 'Video', infoLabels=metadata)
def set_properties(self, url, listitem):
# Set all properties necessary for plugin path playback
item_id = self.item['Id']
item_type = self.item['Type']
play_method = window('emby_%s.playmethod' % url)
window('emby_%s.playmethod' % url, clear=True)
window('emby_%s.json' % url, {
'url': url,
'runtime': str(self.item.get('RunTimeTicks')),
'type': item_type,
'id': item_id,
'refreshid': self.item.get('SeriesId') if item_type == "Episode" else item_id,
'playmethod': play_method
})
self.set_artwork(listitem, item_type)
listitem.setCast(self.API.get_actors())
def set_artwork(self, listitem, item_type):
all_artwork = self.artwork.get_all_artwork(self.item, parent_info=True)
# Set artwork for listitem
if item_type == "Episode":
art = {
'poster': "Series.Primary",
'tvshow.poster': "Series.Primary",
'clearart': "Art",
'tvshow.clearart': "Art",
'clearlogo': "Logo",
'tvshow.clearlogo': "Logo",
'discart': "Disc",
'fanart_image': "Backdrop",
'landscape': "Thumb",
'tvshow.landscape': "Thumb",
'thumb': "Primary"
}
else:
art = {
'poster': "Primary",
'clearart': "Art",
'clearlogo': "Logo",
'discart': "Disc",
'fanart_image': "Backdrop",
'landscape': "Thumb",
'thumb': "Primary"
}
for k_art, e_art in art.items():
if e_art == "Backdrop" and all_artwork[e_art]:
self._set_art(listitem, k_art, all_artwork[e_art][0])
else:
self._set_art(listitem, k_art, all_artwork.get(e_art))
def _set_art(self, listitem, art, path):
if path:
if art in ('fanart_image', 'small_poster', 'tiny_poster',
'medium_landscape', 'medium_poster', 'small_fanartimage',
'medium_fanartimage', 'fanart_noindicators'):
listitem.setProperty(art, path)
else:
listitem.setArt({art: path})
def play_all(self, item_ids, seektime=None, **kwargs):
self.playlist.clear()
started = False
for item_id in item_ids:
listitem = xbmcgui.ListItem()
db_id = None
item = self.emby.getItem(item_id)
play_url = putils.PlayUtils(item, listitem, **kwargs if item_ids.index(item_id) == 0 else {}).get_play_url()
if not play_url:
log.info("Failed to retrieve playurl")
continue
log.info("Playurl: %s", play_url)
with DatabaseConn('emby') as cursor:
item_db = embydb.Embydb_Functions(cursor).getItem_byId(item_id)
db_id = item_db[0] if item_db else None
pbutils = PlaybackUtils(item)
pbutils.set_playlist(play_url, item_id, listitem, seektime if item_ids.index(item_id) == 1 else None, db_id)
if item_ids.index(item_id) == 1 and seektime:
log.info("Seektime detected: %s", self.API.adjust_resume(seektime))
listitem.setProperty('StartOffset', str(self.API.adjust_resume(seektime)))
index = max(pbutils.playlist.getposition(), 0) + 1 # Can return -1
for stack in pbutils.stack:
pbutils.playlist.add(url=stack[0], listitem=stack[1], index=index)
index += 1
if not started:
started = True
item = window('emby_%s.json' % play_url)
item['forcedaudio'] = kwargs.get('AudioStreamIndex')
item['forcedsubs'] = kwargs.get('SubtitleStreamIndex')
window('emby_%s.json' % play_url, value=item)
player = xbmc.Player()
player.play(pbutils.playlist)
if started:
return True