New contextmenu: force playback from PMS
- Visible if using direct paths - You will be able to correctly play videos with several parts, media streams or versions - Fixes #78
This commit is contained in:
parent
00299b58b2
commit
bcc46e4ea1
6 changed files with 78 additions and 55 deletions
|
@ -269,6 +269,7 @@
|
||||||
<string id="30412">Force transcode</string>
|
<string id="30412">Force transcode</string>
|
||||||
<string id="30413">Enable Plex context menu in Kodi</string>
|
<string id="30413">Enable Plex context menu in Kodi</string>
|
||||||
<string id="30414">Could not delete the Plex item. Is item deletion enabled on the Plex Media Server?</string>
|
<string id="30414">Could not delete the Plex item. Is item deletion enabled on the Plex Media Server?</string>
|
||||||
|
<string id="30415">Start playback via PMS</string>
|
||||||
|
|
||||||
<!-- add-on settings -->
|
<!-- add-on settings -->
|
||||||
<string id="30500">Verify Host SSL Certificate (more secure)</string>
|
<string id="30500">Verify Host SSL Certificate (more secure)</string>
|
||||||
|
|
|
@ -299,6 +299,7 @@
|
||||||
<string id="30412">Transkodieren erzwingen</string>
|
<string id="30412">Transkodieren erzwingen</string>
|
||||||
<string id="30413">Plex Kontextmenu in Kodi aktivieren</string>
|
<string id="30413">Plex Kontextmenu in Kodi aktivieren</string>
|
||||||
<string id="30414">Konnte das Element nicht löschen. Ist diese Option auf dem Plex Medien Server aktiviert?</string>
|
<string id="30414">Konnte das Element nicht löschen. Ist diese Option auf dem Plex Medien Server aktiviert?</string>
|
||||||
|
<string id="30415">Wiedergabe via PMS starten</string>
|
||||||
|
|
||||||
|
|
||||||
<string id="33033">Kodi wird jetzt neu gestartet um die Änderungen anzuwenden.</string>
|
<string id="33033">Kodi wird jetzt neu gestartet um die Änderungen anzuwenden.</string>
|
||||||
|
|
|
@ -17,8 +17,49 @@ addonName = 'PlexKodiConnect'
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
# Multiply Plex time by this factor to receive Kodi time
|
||||||
PLEX_TO_KODI_TIMEFACTOR = 1.0 / 1000.0
|
PLEX_TO_KODI_TIMEFACTOR = 1.0 / 1000.0
|
||||||
|
|
||||||
|
# Possible output of Kodi's ListItem.DBTYPE for all video items
|
||||||
|
KODI_VIDEOTYPES = (
|
||||||
|
'video',
|
||||||
|
'movie',
|
||||||
|
'set',
|
||||||
|
'tvshow',
|
||||||
|
'season',
|
||||||
|
'episode',
|
||||||
|
'musicvideo'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Possible output of Kodi's ListItem.DBTYPE for all audio items
|
||||||
|
KODI_AUDIOTYPES = (
|
||||||
|
'music',
|
||||||
|
'song',
|
||||||
|
'album',
|
||||||
|
'artist'
|
||||||
|
)
|
||||||
|
|
||||||
|
ITEMTYPE_FROM_PLEXTYPE = {
|
||||||
|
'movie': 'Movies',
|
||||||
|
'season': 'TVShows',
|
||||||
|
'episode': 'TVShows',
|
||||||
|
'show': 'TVShows',
|
||||||
|
'artist': 'Music',
|
||||||
|
'album': 'Music',
|
||||||
|
'track': 'Music',
|
||||||
|
'song': 'Music'
|
||||||
|
}
|
||||||
|
|
||||||
|
KODITYPE_FROM_PLEXTYPE = {
|
||||||
|
'movie': 'movie',
|
||||||
|
'episode': 'episode',
|
||||||
|
'track': 'song',
|
||||||
|
'artist': 'artist',
|
||||||
|
'album': 'album',
|
||||||
|
'XXXXXX': 'musicvideo',
|
||||||
|
'XXXXXXX': 'genre'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def ConvertPlexToKodiTime(plexTime):
|
def ConvertPlexToKodiTime(plexTime):
|
||||||
"""
|
"""
|
||||||
|
@ -29,44 +70,6 @@ def ConvertPlexToKodiTime(plexTime):
|
||||||
return int(float(plexTime) * PLEX_TO_KODI_TIMEFACTOR)
|
return int(float(plexTime) * PLEX_TO_KODI_TIMEFACTOR)
|
||||||
|
|
||||||
|
|
||||||
def GetItemClassFromType(itemType):
|
|
||||||
classes = {
|
|
||||||
'movie': 'Movies',
|
|
||||||
'season': 'TVShows',
|
|
||||||
'episode': 'TVShows',
|
|
||||||
'show': 'TVShows',
|
|
||||||
'artist': 'Music',
|
|
||||||
'album': 'Music',
|
|
||||||
'track': 'Music',
|
|
||||||
'song': 'Music'
|
|
||||||
}
|
|
||||||
return classes[itemType]
|
|
||||||
|
|
||||||
|
|
||||||
def GetItemClassFromNumber(itemType):
|
|
||||||
classes = {
|
|
||||||
1: 'Movies',
|
|
||||||
4: 'TVShows',
|
|
||||||
}
|
|
||||||
return classes[itemType]
|
|
||||||
|
|
||||||
|
|
||||||
def GetKodiTypeFromPlex(plexItemType):
|
|
||||||
"""
|
|
||||||
As used in playlist.item here: http://kodi.wiki/view/JSON-RPC_API
|
|
||||||
"""
|
|
||||||
classes = {
|
|
||||||
'movie': 'movie',
|
|
||||||
'episode': 'episode',
|
|
||||||
'track': 'song',
|
|
||||||
'artist': 'artist',
|
|
||||||
'album': 'album',
|
|
||||||
'XXXXXX': 'musicvideo',
|
|
||||||
'XXXXXXX': 'genre'
|
|
||||||
}
|
|
||||||
return classes[plexItemType.lower()]
|
|
||||||
|
|
||||||
|
|
||||||
def GetPlexKeyNumber(plexKey):
|
def GetPlexKeyNumber(plexKey):
|
||||||
"""
|
"""
|
||||||
Deconstructs e.g. '/library/metadata/xxxx' to the tuple
|
Deconstructs e.g. '/library/metadata/xxxx' to the tuple
|
||||||
|
|
|
@ -7,8 +7,7 @@ import logging
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
|
|
||||||
import PlexAPI
|
import PlexFunctions as PF
|
||||||
from PlexFunctions import GetPlexMetadata, delete_item_from_pms
|
|
||||||
import embydb_functions as embydb
|
import embydb_functions as embydb
|
||||||
from utils import window, settings, dialog, language as lang, kodiSQL
|
from utils import window, settings, dialog, language as lang, kodiSQL
|
||||||
from dialogs import context
|
from dialogs import context
|
||||||
|
@ -25,7 +24,8 @@ OPTIONS = {
|
||||||
# 'AddFav': lang(30405),
|
# 'AddFav': lang(30405),
|
||||||
# 'RemoveFav': lang(30406),
|
# 'RemoveFav': lang(30406),
|
||||||
# 'RateSong': lang(30407),
|
# 'RateSong': lang(30407),
|
||||||
'Transcode': lang(30412)
|
'Transcode': lang(30412),
|
||||||
|
'PMS_Play': lang(30415) # Use PMS to start playback
|
||||||
}
|
}
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -46,9 +46,6 @@ class ContextMenu(object):
|
||||||
if not self.item_id:
|
if not self.item_id:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.item = GetPlexMetadata(self.item_id)
|
|
||||||
self.api = PlexAPI.API(self.item)
|
|
||||||
|
|
||||||
if self._select_menu():
|
if self._select_menu():
|
||||||
self._action_menu()
|
self._action_menu()
|
||||||
|
|
||||||
|
@ -61,7 +58,6 @@ class ContextMenu(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_item_type(cls):
|
def _get_item_type(cls):
|
||||||
item_type = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
|
item_type = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
|
||||||
|
|
||||||
if not item_type:
|
if not item_type:
|
||||||
if xbmc.getCondVisibility('Container.Content(albums)'):
|
if xbmc.getCondVisibility('Container.Content(albums)'):
|
||||||
item_type = "album"
|
item_type = "album"
|
||||||
|
@ -73,7 +69,6 @@ class ContextMenu(object):
|
||||||
item_type = "picture"
|
item_type = "picture"
|
||||||
else:
|
else:
|
||||||
log.info("item_type is unknown")
|
log.info("item_type is unknown")
|
||||||
|
|
||||||
return item_type
|
return item_type
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -92,6 +87,11 @@ class ContextMenu(object):
|
||||||
# Display select dialog
|
# Display select dialog
|
||||||
options = []
|
options = []
|
||||||
|
|
||||||
|
# if user uses direct paths, give option to initiate playback via PMS
|
||||||
|
if (window('useDirectPaths') == 'true' and
|
||||||
|
self.item_type in PF.KODI_VIDEOTYPES):
|
||||||
|
options.append(OPTIONS['PMS_Play'])
|
||||||
|
|
||||||
# if self.item_type in ("movie", "episode", "song"):
|
# if self.item_type in ("movie", "episode", "song"):
|
||||||
# options.append(OPTIONS['Transcode'])
|
# options.append(OPTIONS['Transcode'])
|
||||||
|
|
||||||
|
@ -116,10 +116,11 @@ class ContextMenu(object):
|
||||||
# Addon settings
|
# Addon settings
|
||||||
options.append(OPTIONS['Addon'])
|
options.append(OPTIONS['Addon'])
|
||||||
|
|
||||||
addon = xbmcaddon.Addon('plugin.video.plexkodiconnect')
|
context_menu = context.ContextMenu(
|
||||||
context_menu = context.ContextMenu("script-emby-context.xml",
|
"script-emby-context.xml",
|
||||||
addon.getAddonInfo('path'),
|
xbmcaddon.Addon(
|
||||||
"default", "1080i")
|
'plugin.video.plexkodiconnect').getAddonInfo('path'),
|
||||||
|
"default", "1080i")
|
||||||
context_menu.set_options(options)
|
context_menu.set_options(options)
|
||||||
context_menu.doModal()
|
context_menu.doModal()
|
||||||
|
|
||||||
|
@ -135,6 +136,9 @@ class ContextMenu(object):
|
||||||
if selected == OPTIONS['Transcode']:
|
if selected == OPTIONS['Transcode']:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
elif selected == OPTIONS['PMS_Play']:
|
||||||
|
self._PMS_play()
|
||||||
|
|
||||||
elif selected == OPTIONS['Refresh']:
|
elif selected == OPTIONS['Refresh']:
|
||||||
self.emby.refreshItem(self.item_id)
|
self.emby.refreshItem(self.item_id)
|
||||||
|
|
||||||
|
@ -192,5 +196,20 @@ class ContextMenu(object):
|
||||||
|
|
||||||
if delete:
|
if delete:
|
||||||
log.info("Deleting Plex item with id %s", self.item_id)
|
log.info("Deleting Plex item with id %s", self.item_id)
|
||||||
if delete_item_from_pms(self.item_id) is False:
|
if PF.delete_item_from_pms(self.item_id) is False:
|
||||||
dialog(type_="ok", heading="{plex}", line1=lang(30414))
|
dialog(type_="ok", heading="{plex}", line1=lang(30414))
|
||||||
|
|
||||||
|
def _PMS_play(self):
|
||||||
|
"""
|
||||||
|
For using direct paths: Initiates playback using the PMS
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
'filename': '/library/metadata/%s' % self.item_id,
|
||||||
|
'id': self.item_id,
|
||||||
|
'dbid': self.kodi_id,
|
||||||
|
'mode': "play"
|
||||||
|
}
|
||||||
|
from urllib import urlencode
|
||||||
|
handle = ("plugin://plugin.video.plexkodiconnect.movies?%s"
|
||||||
|
% urlencode(params))
|
||||||
|
xbmc.executebuiltin('RunPlugin(%s)' % handle)
|
||||||
|
|
|
@ -1623,7 +1623,7 @@ class LibrarySync(Thread):
|
||||||
# Now tell Kodi where we are
|
# Now tell Kodi where we are
|
||||||
for item in items:
|
for item in items:
|
||||||
itemFkt = getattr(itemtypes,
|
itemFkt = getattr(itemtypes,
|
||||||
PF.GetItemClassFromType(item['kodi_type']))
|
PF.ITEMTYPE_FROM_PLEXTYPE[item['kodi_type']])
|
||||||
with itemFkt() as Fkt:
|
with itemFkt() as Fkt:
|
||||||
Fkt.updatePlaystate(item)
|
Fkt.updatePlaystate(item)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import json
|
|
||||||
import sys
|
import sys
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ class PlaybackUtils():
|
||||||
self.pl.insertintoPlaylist(
|
self.pl.insertintoPlaylist(
|
||||||
self.currentPosition+1,
|
self.currentPosition+1,
|
||||||
dbid,
|
dbid,
|
||||||
PF.GetKodiTypeFromPlex(API.getType()))
|
PF.KODITYPE_FROM_PLEXTYPE[API.getType()])
|
||||||
self.currentPosition += 1
|
self.currentPosition += 1
|
||||||
|
|
||||||
############### -- CHECK FOR INTROS ################
|
############### -- CHECK FOR INTROS ################
|
||||||
|
@ -143,7 +142,7 @@ class PlaybackUtils():
|
||||||
log.info("Adding main item to playlist.")
|
log.info("Adding main item to playlist.")
|
||||||
self.pl.addtoPlaylist(
|
self.pl.addtoPlaylist(
|
||||||
dbid,
|
dbid,
|
||||||
PF.GetKodiTypeFromPlex(API.getType()))
|
PF.KODITYPE_FROM_PLEXTYPE[API.getType()])
|
||||||
|
|
||||||
# Ensure that additional parts are played after the main item
|
# Ensure that additional parts are played after the main item
|
||||||
self.currentPosition += 1
|
self.currentPosition += 1
|
||||||
|
|
Loading…
Reference in a new issue