Enable context menu playback
This commit is contained in:
parent
a6a8c18711
commit
bd85bb445e
6 changed files with 94 additions and 120 deletions
|
@ -1,19 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###############################################################################
|
||||
import logging
|
||||
from logging import getLogger
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from xbmc import getInfoLabel, sleep, executebuiltin, getCondVisibility
|
||||
from xbmcaddon import Addon
|
||||
|
||||
import plexdb_functions as plexdb
|
||||
from utils import window, settings, dialog, language as lang, kodiSQL
|
||||
from utils import window, settings, dialog, language as lang
|
||||
from dialogs import context
|
||||
from PlexFunctions import delete_item_from_pms
|
||||
import variables as v
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
LOG = logging.getLogger("PLEX." + __name__)
|
||||
LOG = getLogger("PLEX." + __name__)
|
||||
|
||||
OPTIONS = {
|
||||
'Refresh': lang(30410),
|
||||
|
@ -30,69 +31,74 @@ OPTIONS = {
|
|||
|
||||
|
||||
class ContextMenu(object):
|
||||
|
||||
"""
|
||||
Class initiated if user opens "Plex options" on a PLEX item using the Kodi
|
||||
context menu
|
||||
"""
|
||||
_selected_option = None
|
||||
|
||||
def __init__(self):
|
||||
self.kodi_id = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
|
||||
self.item_type = self._get_item_type()
|
||||
self.item_id = self._get_item_id(self.kodi_id, self.item_type)
|
||||
|
||||
LOG.info("Found item_id: %s item_type: %s",
|
||||
self.item_id, self.item_type)
|
||||
|
||||
if not self.item_id:
|
||||
"""
|
||||
Simply instantiate with ContextMenu() - no need to call any methods
|
||||
"""
|
||||
self.kodi_id = getInfoLabel('ListItem.DBID').decode('utf-8')
|
||||
self.kodi_type = self._get_kodi_type()
|
||||
self.plex_id = self._get_plex_id(self.kodi_id, self.kodi_type)
|
||||
if self.kodi_type:
|
||||
self.plex_type = v.PLEX_TYPE_FROM_KODI_TYPE[self.kodi_type]
|
||||
else:
|
||||
self.plex_type = None
|
||||
LOG.debug("Found plex_id: %s plex_type: %s",
|
||||
self.plex_id, self.plex_type)
|
||||
if not self.plex_id:
|
||||
return
|
||||
|
||||
if self._select_menu():
|
||||
self._action_menu()
|
||||
|
||||
if self._selected_option in (OPTIONS['Delete'],
|
||||
OPTIONS['Refresh']):
|
||||
LOG.info("refreshing container")
|
||||
xbmc.sleep(500)
|
||||
xbmc.executebuiltin('Container.Refresh')
|
||||
sleep(500)
|
||||
executebuiltin('Container.Refresh')
|
||||
|
||||
@classmethod
|
||||
def _get_item_type(cls):
|
||||
item_type = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
|
||||
if not item_type:
|
||||
if xbmc.getCondVisibility('Container.Content(albums)'):
|
||||
item_type = "album"
|
||||
elif xbmc.getCondVisibility('Container.Content(artists)'):
|
||||
item_type = "artist"
|
||||
elif xbmc.getCondVisibility('Container.Content(songs)'):
|
||||
item_type = "song"
|
||||
elif xbmc.getCondVisibility('Container.Content(pictures)'):
|
||||
item_type = "picture"
|
||||
@staticmethod
|
||||
def _get_kodi_type():
|
||||
kodi_type = getInfoLabel('ListItem.DBTYPE').decode('utf-8')
|
||||
if not kodi_type:
|
||||
if getCondVisibility('Container.Content(albums)'):
|
||||
kodi_type = v.KODI_TYPE_ALBUM
|
||||
elif getCondVisibility('Container.Content(artists)'):
|
||||
kodi_type = v.KODI_TYPE_ARTIST
|
||||
elif getCondVisibility('Container.Content(songs)'):
|
||||
kodi_type = v.KODI_TYPE_SONG
|
||||
elif getCondVisibility('Container.Content(pictures)'):
|
||||
kodi_type = v.KODI_TYPE_PHOTO
|
||||
else:
|
||||
LOG.info("item_type is unknown")
|
||||
return item_type
|
||||
LOG.info("kodi_type is unknown")
|
||||
kodi_type = None
|
||||
return kodi_type
|
||||
|
||||
@classmethod
|
||||
def _get_item_id(cls, kodi_id, item_type):
|
||||
item_id = xbmc.getInfoLabel('ListItem.Property(plexid)')
|
||||
if not item_id and kodi_id and item_type:
|
||||
@staticmethod
|
||||
def _get_plex_id(kodi_id, kodi_type):
|
||||
plex_id = getInfoLabel('ListItem.Property(plexid)') or None
|
||||
if not plex_id and kodi_id and kodi_type:
|
||||
with plexdb.Get_Plex_DB() as plexcursor:
|
||||
item = plexcursor.getItem_byKodiId(kodi_id, item_type)
|
||||
item = plexcursor.getItem_byKodiId(kodi_id, kodi_type)
|
||||
try:
|
||||
item_id = item[0]
|
||||
plex_id = item[0]
|
||||
except TypeError:
|
||||
LOG.error('Could not get the Plex id for context menu')
|
||||
return item_id
|
||||
LOG.info('Could not get the Plex id for context menu')
|
||||
return plex_id
|
||||
|
||||
def _select_menu(self):
|
||||
# Display select dialog
|
||||
"""
|
||||
Display select dialog
|
||||
"""
|
||||
options = []
|
||||
|
||||
# if user uses direct paths, give option to initiate playback via PMS
|
||||
if (window('useDirectPaths') == 'true' and
|
||||
self.item_type in v.KODI_VIDEOTYPES):
|
||||
if state.DIRECT_PATHS and self.kodi_type in v.KODI_VIDEOTYPES:
|
||||
options.append(OPTIONS['PMS_Play'])
|
||||
|
||||
if self.item_type in v.KODI_VIDEOTYPES:
|
||||
if self.kodi_type in v.KODI_VIDEOTYPES:
|
||||
options.append(OPTIONS['Transcode'])
|
||||
|
||||
# userdata = self.api.getUserData()
|
||||
# if userdata['Favorite']:
|
||||
# # Remove from emby favourites
|
||||
|
@ -100,11 +106,9 @@ class ContextMenu(object):
|
|||
# else:
|
||||
# # Add to emby favourites
|
||||
# options.append(OPTIONS['AddFav'])
|
||||
|
||||
# if self.item_type == "song":
|
||||
# if self.kodi_type == "song":
|
||||
# # Set custom song rating
|
||||
# options.append(OPTIONS['RateSong'])
|
||||
|
||||
# Refresh item
|
||||
# options.append(OPTIONS['Refresh'])
|
||||
# Delete item, only if the Plex Home main user is logged in
|
||||
|
@ -113,103 +117,65 @@ class ContextMenu(object):
|
|||
options.append(OPTIONS['Delete'])
|
||||
# Addon settings
|
||||
options.append(OPTIONS['Addon'])
|
||||
|
||||
context_menu = context.ContextMenu(
|
||||
"script-emby-context.xml",
|
||||
xbmcaddon.Addon(
|
||||
'plugin.video.plexkodiconnect').getAddonInfo('path'),
|
||||
"default", "1080i")
|
||||
Addon('plugin.video.plexkodiconnect').getAddonInfo('path'),
|
||||
"default",
|
||||
"1080i")
|
||||
context_menu.set_options(options)
|
||||
context_menu.doModal()
|
||||
|
||||
if context_menu.is_selected():
|
||||
self._selected_option = context_menu.get_selected()
|
||||
|
||||
return self._selected_option
|
||||
|
||||
def _action_menu(self):
|
||||
|
||||
"""
|
||||
Do whatever the user selected to do
|
||||
"""
|
||||
selected = self._selected_option
|
||||
|
||||
if selected == OPTIONS['Transcode']:
|
||||
window('plex_forcetranscode', value='true')
|
||||
state.FORCE_TRANSCODE = True
|
||||
self._PMS_play()
|
||||
|
||||
elif selected == OPTIONS['PMS_Play']:
|
||||
self._PMS_play()
|
||||
|
||||
# elif selected == OPTIONS['Refresh']:
|
||||
# self.emby.refreshItem(self.item_id)
|
||||
|
||||
# elif selected == OPTIONS['AddFav']:
|
||||
# self.emby.updateUserRating(self.item_id, favourite=True)
|
||||
|
||||
# elif selected == OPTIONS['RemoveFav']:
|
||||
# self.emby.updateUserRating(self.item_id, favourite=False)
|
||||
|
||||
# elif selected == OPTIONS['RateSong']:
|
||||
# self._rate_song()
|
||||
|
||||
elif selected == OPTIONS['Addon']:
|
||||
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
|
||||
executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
elif selected == OPTIONS['Delete']:
|
||||
self._delete_item()
|
||||
|
||||
def _rate_song(self):
|
||||
|
||||
conn = kodiSQL('music')
|
||||
cursor = conn.cursor()
|
||||
query = "SELECT rating FROM song WHERE idSong = ?"
|
||||
cursor.execute(query, (self.kodi_id,))
|
||||
try:
|
||||
value = cursor.fetchone()[0]
|
||||
current_value = int(round(float(value), 0))
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
new_value = dialog("numeric", 0, lang(30411), str(current_value))
|
||||
if new_value > -1:
|
||||
|
||||
new_value = int(new_value)
|
||||
if new_value > 5:
|
||||
new_value = 5
|
||||
|
||||
if settings('enableUpdateSongRating') == "true":
|
||||
musicutils.updateRatingToFile(new_value, self.api.get_file_path())
|
||||
|
||||
query = "UPDATE song SET rating = ? WHERE idSong = ?"
|
||||
cursor.execute(query, (new_value, self.kodi_id,))
|
||||
conn.commit()
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
def _delete_item(self):
|
||||
|
||||
"""
|
||||
Delete item on PMS
|
||||
"""
|
||||
delete = True
|
||||
if settings('skipContextMenu') != "true":
|
||||
|
||||
if not dialog("yesno", heading=lang(29999), line1=lang(33041)):
|
||||
LOG.info("User skipped deletion for: %s", self.item_id)
|
||||
if not dialog("yesno", heading="{plex}", line1=lang(33041)):
|
||||
LOG.info("User skipped deletion for: %s", self.plex_id)
|
||||
delete = False
|
||||
|
||||
if delete:
|
||||
LOG.info("Deleting Plex item with id %s", self.item_id)
|
||||
if delete_item_from_pms(self.item_id) is False:
|
||||
LOG.info("Deleting Plex item with id %s", self.plex_id)
|
||||
if delete_item_from_pms(self.plex_id) is False:
|
||||
dialog("ok", heading="{plex}", line1=lang(30414))
|
||||
|
||||
def _PMS_play(self):
|
||||
"""
|
||||
For using direct paths: Initiates playback using the PMS
|
||||
"""
|
||||
window('plex_contextplay', value='true')
|
||||
state.CONTEXT_MENU_PLAY = True
|
||||
params = {
|
||||
'filename': '/library/metadata/%s' % self.item_id,
|
||||
'id': self.item_id,
|
||||
'dbid': self.kodi_id,
|
||||
'mode': "play"
|
||||
'mode': 'play',
|
||||
'plex_id': self.plex_id,
|
||||
'plex_type': self.plex_type
|
||||
}
|
||||
from urllib import urlencode
|
||||
handle = ("plugin://plugin.video.plexkodiconnect/movies?%s"
|
||||
% urlencode(params))
|
||||
xbmc.executebuiltin('RunPlugin(%s)' % handle)
|
||||
executebuiltin('RunPlugin(%s)' % handle)
|
||||
|
|
|
@ -17,7 +17,7 @@ from playutils import PlayUtils
|
|||
from PKC_listitem import PKC_ListItem
|
||||
from pickler import pickle_me, Playback_Successful
|
||||
import json_rpc as js
|
||||
from utils import window, settings, dialog, language as lang, tryEncode
|
||||
from utils import settings, dialog, language as lang, tryEncode
|
||||
from plexbmchelper.subscribers import LOCKER
|
||||
import variables as v
|
||||
import state
|
||||
|
@ -120,8 +120,6 @@ def playback_init(plex_id, plex_type, playqueue):
|
|||
Playback setup if Kodi starts playing an item for the first time.
|
||||
"""
|
||||
LOG.info('Initializing PKC playback')
|
||||
contextmenu_play = window('plex_contextplay') == 'true'
|
||||
window('plex_contextplay', clear=True)
|
||||
xml = GetPlexMetadata(plex_id)
|
||||
try:
|
||||
xml[0].attrib
|
||||
|
@ -158,6 +156,9 @@ def playback_init(plex_id, plex_type, playqueue):
|
|||
# Sleep a bit to let setResolvedUrl do its thing - bit ugly
|
||||
sleep(200)
|
||||
_process_stack(playqueue, stack)
|
||||
# Reset some playback variables
|
||||
state.CONTEXT_MENU_PLAY = False
|
||||
state.FORCE_TRANSCODE = False
|
||||
# New thread to release this one sooner (e.g. harddisk spinning up)
|
||||
thread = Thread(target=Player().play,
|
||||
args=(playqueue.kodi_pl, ))
|
||||
|
@ -176,7 +177,10 @@ def _prep_playlist_stack(xml):
|
|||
stack = []
|
||||
for item in xml:
|
||||
api = API(item)
|
||||
if api.getType() != v.PLEX_TYPE_CLIP:
|
||||
if (state.CONTEXT_MENU_PLAY is False or
|
||||
api.getType() != v.PLEX_TYPE_CLIP):
|
||||
# If user chose to play via PMS or force transcode, do not
|
||||
# use the item path stored in the Kodi DB
|
||||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
plex_dbitem = plex_db.getItem_byId(api.getRatingKey())
|
||||
kodi_id = plex_dbitem[0] if plex_dbitem else None
|
||||
|
@ -243,6 +247,7 @@ def _process_stack(playqueue, stack, fill_queue=False):
|
|||
playlist_item.offset = item['offset']
|
||||
playlist_item.part = item['part']
|
||||
playlist_item.id = item['id']
|
||||
playlist_item.force_transcode = state.FORCE_TRANSCODE
|
||||
playlist_item.init_done = True
|
||||
pos += 1
|
||||
if fill_queue:
|
||||
|
@ -356,7 +361,8 @@ def process_indirect(key, offset, resolve=True):
|
|||
pickle_me(result)
|
||||
else:
|
||||
thread = Thread(target=Player().play,
|
||||
args={'item': tryEncode(playurl), 'listitem': listitem})
|
||||
args={'item': tryEncode(playurl),
|
||||
'listitem': listitem})
|
||||
thread.setDaemon(True)
|
||||
LOG.info('Done initializing PKC playback, starting Kodi player')
|
||||
thread.start()
|
||||
|
|
|
@ -5,7 +5,6 @@ from logging import getLogger
|
|||
|
||||
from xbmc import Player
|
||||
|
||||
from utils import window
|
||||
from downloadutils import DownloadUtils as DU
|
||||
from plexbmchelper.subscribers import LOCKER
|
||||
import variables as v
|
||||
|
@ -26,10 +25,6 @@ def playback_cleanup():
|
|||
# We might have saved a transient token from a user flinging media via
|
||||
# Companion (if we could not use the playqueue to store the token)
|
||||
state.PLEX_TRANSIENT_TOKEN = None
|
||||
for item in ('plex_customplaylist',
|
||||
'plex_customplaylist.seektime',
|
||||
'plex_forcetranscode'):
|
||||
window(item, clear=True)
|
||||
for playerid in state.ACTIVE_PLAYERS:
|
||||
status = state.PLAYER_STATES[playerid]
|
||||
# Remember the last played item later
|
||||
|
|
|
@ -197,6 +197,7 @@ class Playlist_Item(object):
|
|||
playcount = None [int] how many times the item has already been played
|
||||
offset = None [int] the item's view offset UPON START in Plex time
|
||||
part = 0 [int] part number if Plex video consists of mult. parts
|
||||
force_transcode [bool] defaults to False
|
||||
init_done = False Set to True only if run through playback init
|
||||
"""
|
||||
def __init__(self):
|
||||
|
@ -215,6 +216,7 @@ class Playlist_Item(object):
|
|||
self.offset = None
|
||||
# If Plex video consists of several parts; part number
|
||||
self.part = 0
|
||||
self.force_transcode = False
|
||||
self.init_done = False
|
||||
|
||||
def __repr__(self):
|
||||
|
|
|
@ -87,7 +87,8 @@ class PlayUtils():
|
|||
- codec is in h265
|
||||
- 10bit video codec
|
||||
- HEVC codec
|
||||
- window variable 'plex_forcetranscode' set to 'true'
|
||||
- playqueue_item force_transcode is set to True
|
||||
- state variable FORCE_TRANSCODE set to True
|
||||
(excepting trailers etc.)
|
||||
- video bitrate above specified settings bitrate
|
||||
if the corresponding file settings are set to 'true'
|
||||
|
@ -97,7 +98,7 @@ class PlayUtils():
|
|||
return False
|
||||
videoCodec = self.api.getVideoCodec()
|
||||
LOG.info("videoCodec: %s" % videoCodec)
|
||||
if window('plex_forcetranscode') == 'true':
|
||||
if self.item.force_transcode is True:
|
||||
LOG.info('User chose to force-transcode')
|
||||
return True
|
||||
codec = videoCodec['videocodec']
|
||||
|
|
|
@ -143,6 +143,10 @@ RESUMABLE = False
|
|||
# Set by SpecialMonitor - did user choose to resume playback or start from the
|
||||
# beginning?
|
||||
RESUME_PLAYBACK = False
|
||||
# Was the playback initiated by the user using the Kodi context menu?
|
||||
CONTEXT_MENU_PLAY = False
|
||||
# Set by context menu - shall we force-transcode the next playing item?
|
||||
FORCE_TRANSCODE = False
|
||||
|
||||
# Kodi webserver details
|
||||
WEBSERVER_PORT = 8080
|
||||
|
|
Loading…
Reference in a new issue