2018-07-13 02:46:02 +10:00
|
|
|
#!/usr/bin/env python
|
2017-01-25 02:04:42 +11:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-07-13 02:46:02 +10:00
|
|
|
from __future__ import absolute_import, division, unicode_literals
|
2018-05-01 22:48:49 +10:00
|
|
|
import os
|
2018-06-24 02:25:18 +10:00
|
|
|
import sys
|
2019-02-06 04:52:10 +11:00
|
|
|
import platform
|
2019-01-13 23:41:22 +11:00
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
import xbmc
|
2017-01-25 02:53:50 +11:00
|
|
|
from xbmcaddon import Addon
|
|
|
|
|
2019-01-13 23:41:22 +11:00
|
|
|
from . import path_ops
|
|
|
|
|
2017-05-21 04:24:47 +10:00
|
|
|
# Paths are in unicode, otherwise Windows will throw fits
|
|
|
|
# For any file operations with KODI function, use encoded strings!
|
2017-05-04 04:30:33 +10:00
|
|
|
|
2017-01-29 23:58:55 +11:00
|
|
|
|
2018-02-11 22:59:04 +11:00
|
|
|
def try_decode(string, encoding='utf-8'):
|
2017-01-29 23:58:55 +11:00
|
|
|
"""
|
|
|
|
Will try to decode string (encoded) using encoding. This possibly
|
|
|
|
fails with e.g. Android TV's Python, which does not accept arguments for
|
|
|
|
string.encode()
|
|
|
|
"""
|
|
|
|
if isinstance(string, unicode):
|
|
|
|
# already decoded
|
|
|
|
return string
|
|
|
|
try:
|
|
|
|
string = string.decode(encoding, "ignore")
|
|
|
|
except TypeError:
|
|
|
|
string = string.decode()
|
|
|
|
return string
|
|
|
|
|
2018-02-06 03:48:50 +11:00
|
|
|
|
|
|
|
# Percent of playback progress for watching item as partially watched. Anything
|
|
|
|
# more and item will NOT be marked as partially, but fully watched
|
2017-09-24 02:40:30 +10:00
|
|
|
MARK_PLAYED_AT = 0.9
|
2018-02-06 03:48:50 +11:00
|
|
|
# How many seconds of playback do we ignore before marking an item as partially
|
|
|
|
# watched?
|
|
|
|
IGNORE_SECONDS_AT_START = 60
|
2017-01-29 23:58:55 +11:00
|
|
|
|
|
|
|
_ADDON = Addon()
|
2017-01-25 02:53:50 +11:00
|
|
|
ADDON_NAME = 'PlexKodiConnect'
|
|
|
|
ADDON_ID = 'plugin.video.plexkodiconnect'
|
2017-01-29 23:58:55 +11:00
|
|
|
ADDON_VERSION = _ADDON.getAddonInfo('version')
|
2018-06-24 02:25:18 +10:00
|
|
|
ADDON_PATH = try_decode(_ADDON.getAddonInfo('path'))
|
2018-03-28 03:07:16 +11:00
|
|
|
ADDON_FOLDER = try_decode(xbmc.translatePath('special://home'))
|
2018-07-05 20:52:02 +10:00
|
|
|
ADDON_PROFILE = try_decode(xbmc.translatePath(_ADDON.getAddonInfo('profile')))
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1)
|
|
|
|
KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
|
2017-01-25 04:48:13 +11:00
|
|
|
KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion')
|
2018-02-11 22:59:04 +11:00
|
|
|
KODI_PROFILE = try_decode(xbmc.translatePath("special://profile"))
|
2017-01-25 02:04:42 +11:00
|
|
|
|
2017-01-25 02:53:50 +11:00
|
|
|
if xbmc.getCondVisibility('system.platform.osx'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "MacOSX"
|
2018-08-08 04:02:44 +10:00
|
|
|
elif xbmc.getCondVisibility("system.platform.uwp"):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "Microsoft UWP"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.atv2'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "AppleTV2"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.ios'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "iOS"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.windows'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "Windows"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.raspberrypi'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "RaspberryPi"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.linux'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "Linux"
|
2017-01-25 02:53:50 +11:00
|
|
|
elif xbmc.getCondVisibility('system.platform.android'):
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "Android"
|
2017-01-25 02:53:50 +11:00
|
|
|
else:
|
2019-02-06 04:52:10 +11:00
|
|
|
DEVICE = "Unknown"
|
|
|
|
|
|
|
|
MODEL = platform.release() or 'Unknown'
|
|
|
|
# Plex' own platform for e.g. Plex Media Player
|
|
|
|
PLATFORM = 'Konvergo'
|
|
|
|
PLATFORM_VERSION = '2.26.0.947-1e21fa2b'
|
2017-01-25 02:53:50 +11:00
|
|
|
|
2018-02-11 22:59:04 +11:00
|
|
|
DEVICENAME = try_decode(_ADDON.getSetting('deviceName'))
|
2018-11-06 23:43:40 +11:00
|
|
|
if not DEVICENAME:
|
|
|
|
DEVICENAME = try_decode(xbmc.getInfoLabel('System.FriendlyName'))
|
|
|
|
_ADDON.setSetting('deviceName', DEVICENAME)
|
2017-03-06 01:30:06 +11:00
|
|
|
DEVICENAME = DEVICENAME.replace(":", "")
|
|
|
|
DEVICENAME = DEVICENAME.replace("/", "-")
|
|
|
|
DEVICENAME = DEVICENAME.replace("\\", "-")
|
|
|
|
DEVICENAME = DEVICENAME.replace("<", "")
|
|
|
|
DEVICENAME = DEVICENAME.replace(">", "")
|
|
|
|
DEVICENAME = DEVICENAME.replace("*", "")
|
|
|
|
DEVICENAME = DEVICENAME.replace("?", "")
|
|
|
|
DEVICENAME = DEVICENAME.replace('|', "")
|
|
|
|
DEVICENAME = DEVICENAME.replace('(', "")
|
|
|
|
DEVICENAME = DEVICENAME.replace(')', "")
|
2018-01-02 03:15:01 +11:00
|
|
|
DEVICENAME = DEVICENAME.replace(' ', "")
|
2017-01-25 02:53:50 +11:00
|
|
|
|
2017-12-10 02:30:52 +11:00
|
|
|
COMPANION_PORT = int(_ADDON.getSetting('companionPort'))
|
|
|
|
|
2019-03-26 03:15:18 +11:00
|
|
|
# Port for the PKC webservice
|
|
|
|
WEBSERVICE_PORT = 57578
|
|
|
|
|
2017-12-10 02:18:46 +11:00
|
|
|
# Unique ID for this Plex client; also see clientinfo.py
|
|
|
|
PKC_MACHINE_IDENTIFIER = None
|
|
|
|
|
2018-02-09 23:57:58 +11:00
|
|
|
# Minimal PKC version needed for the Kodi database - otherwise need to recreate
|
2019-03-30 00:03:46 +11:00
|
|
|
MIN_DB_VERSION = '2.6.8'
|
2018-02-09 23:57:58 +11:00
|
|
|
|
2019-02-24 21:18:48 +11:00
|
|
|
# Supported databases - version numbers in tuples should decrease
|
2019-01-13 23:41:22 +11:00
|
|
|
SUPPORTED_VIDEO_DB = {
|
|
|
|
# Kodi 17 Krypton:
|
2019-02-24 21:18:48 +11:00
|
|
|
17: (107, ),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 18 Leia:
|
2019-02-24 21:18:48 +11:00
|
|
|
18: (116, 113),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 19 - EXTREMLY EXPERIMENTAL!
|
2019-02-24 21:18:48 +11:00
|
|
|
19: (116, 113)
|
2017-01-29 23:40:34 +11:00
|
|
|
}
|
2019-01-13 23:41:22 +11:00
|
|
|
SUPPORTED_MUSIC_DB = {
|
|
|
|
# Kodi 17 Krypton:
|
2019-02-24 21:18:48 +11:00
|
|
|
17: (60, ),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 18 Leia:
|
2019-02-24 21:18:48 +11:00
|
|
|
18: (72, ),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 19 - EXTREMLY EXPERIMENTAL!
|
2019-02-24 21:18:48 +11:00
|
|
|
19: (72, )
|
2017-01-29 23:40:34 +11:00
|
|
|
}
|
2019-01-13 23:41:22 +11:00
|
|
|
SUPPORTED_TEXTURE_DB = {
|
|
|
|
# Kodi 17 Krypton:
|
2019-02-24 21:18:48 +11:00
|
|
|
17: (13, ),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 18 Leia:
|
2019-02-24 21:18:48 +11:00
|
|
|
18: (13, ),
|
2019-01-13 23:41:22 +11:00
|
|
|
# Kodi 19 - EXTREMLY EXPERIMENTAL!
|
2019-02-24 21:18:48 +11:00
|
|
|
19: (13, )
|
2017-01-29 23:40:34 +11:00
|
|
|
}
|
2019-01-13 23:41:22 +11:00
|
|
|
DB_VIDEO_VERSION = None
|
|
|
|
DB_VIDEO_PATH = None
|
|
|
|
DB_MUSIC_VERSION = None
|
|
|
|
DB_MUSIC_PATH = None
|
|
|
|
DB_TEXTURE_VERSION = None
|
|
|
|
DB_TEXTURE_PATH = None
|
2018-02-11 22:59:04 +11:00
|
|
|
DB_PLEX_PATH = try_decode(xbmc.translatePath("special://database/plex.db"))
|
2017-01-29 23:40:34 +11:00
|
|
|
|
2018-02-11 22:59:04 +11:00
|
|
|
EXTERNAL_SUBTITLE_TEMP_PATH = try_decode(xbmc.translatePath(
|
2017-05-21 04:24:47 +10:00
|
|
|
"special://profile/addon_data/%s/temp/" % ADDON_ID))
|
2017-05-01 21:07:41 +10:00
|
|
|
|
2017-01-29 23:40:34 +11:00
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
# Multiply Plex time by this factor to receive Kodi time
|
|
|
|
PLEX_TO_KODI_TIMEFACTOR = 1.0 / 1000.0
|
|
|
|
|
2018-05-01 22:48:49 +10:00
|
|
|
# Playlist stuff
|
2018-05-01 23:13:42 +10:00
|
|
|
PLAYLIST_PATH = os.path.join(KODI_PROFILE, 'playlists')
|
2018-05-01 22:48:49 +10:00
|
|
|
PLAYLIST_PATH_MIXED = os.path.join(PLAYLIST_PATH, 'mixed')
|
|
|
|
PLAYLIST_PATH_VIDEO = os.path.join(PLAYLIST_PATH, 'video')
|
|
|
|
PLAYLIST_PATH_MUSIC = os.path.join(PLAYLIST_PATH, 'music')
|
|
|
|
|
|
|
|
PLEX_TYPE_AUDIO_PLAYLIST = 'audio'
|
|
|
|
PLEX_TYPE_VIDEO_PLAYLIST = 'video'
|
2018-08-04 02:37:16 +10:00
|
|
|
PLEX_TYPE_PHOTO_PLAYLIST = 'photo'
|
2018-05-01 22:48:49 +10:00
|
|
|
KODI_TYPE_AUDIO_PLAYLIST = 'music'
|
|
|
|
KODI_TYPE_VIDEO_PLAYLIST = 'video'
|
2018-08-04 02:37:16 +10:00
|
|
|
KODI_TYPE_PHOTO_PLAYLIST = None # Not supported yet
|
2018-05-01 22:48:49 +10:00
|
|
|
KODI_PLAYLIST_TYPE_FROM_PLEX = {
|
|
|
|
PLEX_TYPE_AUDIO_PLAYLIST: KODI_TYPE_AUDIO_PLAYLIST,
|
|
|
|
PLEX_TYPE_VIDEO_PLAYLIST: KODI_TYPE_VIDEO_PLAYLIST
|
|
|
|
}
|
2018-05-03 02:50:31 +10:00
|
|
|
PLEX_PLAYLIST_TYPE_FROM_KODI = {
|
|
|
|
KODI_TYPE_AUDIO_PLAYLIST: PLEX_TYPE_AUDIO_PLAYLIST,
|
|
|
|
KODI_TYPE_VIDEO_PLAYLIST: PLEX_TYPE_VIDEO_PLAYLIST
|
|
|
|
}
|
2018-05-01 22:48:49 +10:00
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
# All the Plex types as communicated in the PMS xml replies
|
|
|
|
PLEX_TYPE_VIDEO = 'video'
|
|
|
|
PLEX_TYPE_MOVIE = 'movie'
|
|
|
|
PLEX_TYPE_CLIP = 'clip' # e.g. trailers
|
2018-07-05 20:46:40 +10:00
|
|
|
PLEX_TYPE_SET = 'collection' # sets/collections
|
2018-07-28 00:01:05 +10:00
|
|
|
PLEX_TYPE_MIXED = 'mixed'
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
PLEX_TYPE_EPISODE = 'episode'
|
|
|
|
PLEX_TYPE_SEASON = 'season'
|
|
|
|
PLEX_TYPE_SHOW = 'show'
|
|
|
|
|
|
|
|
PLEX_TYPE_AUDIO = 'music'
|
|
|
|
PLEX_TYPE_SONG = 'track'
|
|
|
|
PLEX_TYPE_ALBUM = 'album'
|
|
|
|
PLEX_TYPE_ARTIST = 'artist'
|
2017-03-09 02:21:00 +11:00
|
|
|
PLEX_TYPE_MUSICVIDEO = 'musicvideo'
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
PLEX_TYPE_PHOTO = 'photo'
|
|
|
|
|
2019-01-09 04:00:54 +11:00
|
|
|
PLEX_TYPE_PLAYLIST = 'playlist'
|
|
|
|
PLEX_TYPE_CHANNEL = 'channel'
|
|
|
|
|
2018-01-01 23:28:39 +11:00
|
|
|
# Used for /:/timeline XML messages
|
|
|
|
PLEX_PLAYLIST_TYPE_VIDEO = 'video'
|
|
|
|
PLEX_PLAYLIST_TYPE_AUDIO = 'music'
|
|
|
|
PLEX_PLAYLIST_TYPE_PHOTO = 'photo'
|
|
|
|
|
|
|
|
KODI_PLAYLIST_TYPE_VIDEO = 'video'
|
|
|
|
KODI_PLAYLIST_TYPE_AUDIO = 'audio'
|
|
|
|
KODI_PLAYLIST_TYPE_PHOTO = 'picture'
|
|
|
|
|
|
|
|
KODI_PLAYLIST_TYPE_FROM_PLEX_PLAYLIST_TYPE = {
|
|
|
|
PLEX_PLAYLIST_TYPE_VIDEO: KODI_PLAYLIST_TYPE_VIDEO,
|
|
|
|
PLEX_PLAYLIST_TYPE_AUDIO: KODI_PLAYLIST_TYPE_AUDIO,
|
|
|
|
PLEX_PLAYLIST_TYPE_PHOTO: KODI_PLAYLIST_TYPE_PHOTO
|
|
|
|
}
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
# All the Kodi types as e.g. used in the JSON API
|
|
|
|
KODI_TYPE_VIDEO = 'video'
|
|
|
|
KODI_TYPE_MOVIE = 'movie'
|
|
|
|
KODI_TYPE_SET = 'set' # for movie sets of several movies
|
|
|
|
KODI_TYPE_CLIP = 'clip' # e.g. trailers
|
|
|
|
|
|
|
|
KODI_TYPE_EPISODE = 'episode'
|
|
|
|
KODI_TYPE_SEASON = 'season'
|
|
|
|
KODI_TYPE_SHOW = 'tvshow'
|
|
|
|
|
|
|
|
KODI_TYPE_AUDIO = 'audio'
|
|
|
|
KODI_TYPE_SONG = 'song'
|
|
|
|
KODI_TYPE_ALBUM = 'album'
|
|
|
|
KODI_TYPE_ARTIST = 'artist'
|
2017-03-09 02:21:00 +11:00
|
|
|
KODI_TYPE_MUSICVIDEO = 'musicvideo'
|
2017-01-25 02:04:42 +11:00
|
|
|
|
|
|
|
KODI_TYPE_PHOTO = 'photo'
|
|
|
|
|
2019-01-09 04:00:54 +11:00
|
|
|
KODI_TYPE_PLAYLIST = 'playlist'
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
KODI_VIDEOTYPES = (
|
|
|
|
KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_MOVIE,
|
|
|
|
KODI_TYPE_SHOW,
|
|
|
|
KODI_TYPE_SEASON,
|
|
|
|
KODI_TYPE_EPISODE,
|
2018-07-28 00:01:05 +10:00
|
|
|
KODI_TYPE_SET,
|
|
|
|
KODI_TYPE_CLIP
|
2017-01-25 02:04:42 +11:00
|
|
|
)
|
|
|
|
|
2018-03-04 00:40:12 +11:00
|
|
|
PLEX_VIDEOTYPES = (
|
2018-07-28 00:01:05 +10:00
|
|
|
PLEX_TYPE_VIDEO,
|
2018-03-04 00:40:12 +11:00
|
|
|
PLEX_TYPE_MOVIE,
|
2018-07-28 00:01:05 +10:00
|
|
|
PLEX_TYPE_SHOW,
|
2018-03-04 00:40:12 +11:00
|
|
|
PLEX_TYPE_SEASON,
|
2018-07-28 00:01:05 +10:00
|
|
|
PLEX_TYPE_EPISODE,
|
|
|
|
PLEX_TYPE_SET,
|
|
|
|
PLEX_TYPE_CLIP,
|
|
|
|
PLEX_TYPE_MIXED, # MIXED SEEMS TO ALWAYS REFER TO VIDEO!
|
2018-03-04 00:40:12 +11:00
|
|
|
)
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
KODI_AUDIOTYPES = (
|
|
|
|
KODI_TYPE_SONG,
|
|
|
|
KODI_TYPE_ALBUM,
|
|
|
|
KODI_TYPE_ARTIST,
|
|
|
|
)
|
|
|
|
|
2018-07-28 00:01:05 +10:00
|
|
|
PLEX_AUDIOTYPES = (
|
|
|
|
PLEX_TYPE_SONG,
|
|
|
|
PLEX_TYPE_ALBUM,
|
|
|
|
PLEX_TYPE_ARTIST,
|
|
|
|
)
|
|
|
|
|
2018-02-22 06:24:31 +11:00
|
|
|
# Translation tables
|
|
|
|
|
|
|
|
ADDON_TYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 'plugin.video.plexkodiconnect.movies',
|
|
|
|
PLEX_TYPE_CLIP: 'plugin.video.plexkodiconnect.movies',
|
2018-02-23 03:38:52 +11:00
|
|
|
PLEX_TYPE_EPISODE: 'plugin.video.plexkodiconnect.tvshows',
|
2019-01-09 04:00:54 +11:00
|
|
|
PLEX_TYPE_SEASON: 'plugin.video.plexkodiconnect.tvshows',
|
|
|
|
PLEX_TYPE_SHOW: 'plugin.video.plexkodiconnect.tvshows',
|
|
|
|
PLEX_TYPE_SONG: 'plugin.video.plexkodiconnect',
|
|
|
|
PLEX_TYPE_ALBUM: 'plugin.video.plexkodiconnect',
|
|
|
|
PLEX_TYPE_ARTIST: 'plugin.video.plexkodiconnect',
|
|
|
|
PLEX_TYPE_PLAYLIST: 'plugin.video.plexkodiconnect'
|
2018-02-22 06:24:31 +11:00
|
|
|
}
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
ITEMTYPE_FROM_PLEXTYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 'Movies',
|
|
|
|
PLEX_TYPE_SEASON: 'TVShows',
|
|
|
|
KODI_TYPE_EPISODE: 'TVShows',
|
|
|
|
PLEX_TYPE_SHOW: 'TVShows',
|
|
|
|
PLEX_TYPE_ARTIST: 'Music',
|
|
|
|
PLEX_TYPE_ALBUM: 'Music',
|
|
|
|
PLEX_TYPE_SONG: 'Music',
|
|
|
|
}
|
|
|
|
|
|
|
|
ITEMTYPE_FROM_KODITYPE = {
|
|
|
|
KODI_TYPE_MOVIE: 'Movies',
|
|
|
|
KODI_TYPE_SEASON: 'TVShows',
|
|
|
|
KODI_TYPE_EPISODE: 'TVShows',
|
|
|
|
KODI_TYPE_SHOW: 'TVShows',
|
|
|
|
KODI_TYPE_ARTIST: 'Music',
|
|
|
|
KODI_TYPE_ALBUM: 'Music',
|
|
|
|
KODI_TYPE_SONG: 'Music',
|
|
|
|
}
|
|
|
|
|
|
|
|
KODITYPE_FROM_PLEXTYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: KODI_TYPE_MOVIE,
|
2019-01-09 04:00:54 +11:00
|
|
|
PLEX_TYPE_CLIP: KODI_TYPE_CLIP,
|
2017-01-25 02:04:42 +11:00
|
|
|
PLEX_TYPE_EPISODE: KODI_TYPE_EPISODE,
|
|
|
|
PLEX_TYPE_SEASON: KODI_TYPE_SEASON,
|
|
|
|
PLEX_TYPE_SHOW: KODI_TYPE_SHOW,
|
|
|
|
PLEX_TYPE_SONG: KODI_TYPE_SONG,
|
|
|
|
PLEX_TYPE_ARTIST: KODI_TYPE_ARTIST,
|
|
|
|
PLEX_TYPE_ALBUM: KODI_TYPE_ALBUM,
|
|
|
|
PLEX_TYPE_PHOTO: KODI_TYPE_PHOTO,
|
|
|
|
'XXXXXX': 'musicvideo',
|
2019-01-09 04:00:54 +11:00
|
|
|
'XXXXXXX': 'genre',
|
|
|
|
PLEX_TYPE_PLAYLIST: KODI_TYPE_PLAYLIST
|
2017-01-25 02:04:42 +11:00
|
|
|
}
|
|
|
|
|
2017-12-14 06:14:27 +11:00
|
|
|
PLEX_TYPE_FROM_KODI_TYPE = {
|
|
|
|
KODI_TYPE_VIDEO: PLEX_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_MOVIE: PLEX_TYPE_MOVIE,
|
2018-07-05 20:46:40 +10:00
|
|
|
KODI_TYPE_SET: PLEX_TYPE_SET,
|
2017-12-14 06:14:27 +11:00
|
|
|
KODI_TYPE_EPISODE: PLEX_TYPE_EPISODE,
|
|
|
|
KODI_TYPE_SEASON: PLEX_TYPE_SEASON,
|
|
|
|
KODI_TYPE_SHOW: PLEX_TYPE_SHOW,
|
|
|
|
KODI_TYPE_CLIP: PLEX_TYPE_CLIP,
|
|
|
|
KODI_TYPE_ARTIST: PLEX_TYPE_ARTIST,
|
|
|
|
KODI_TYPE_ALBUM: PLEX_TYPE_ALBUM,
|
|
|
|
KODI_TYPE_SONG: PLEX_TYPE_SONG,
|
|
|
|
KODI_TYPE_AUDIO: PLEX_TYPE_AUDIO,
|
|
|
|
KODI_TYPE_PHOTO: PLEX_TYPE_PHOTO
|
|
|
|
}
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE = {
|
|
|
|
PLEX_TYPE_VIDEO: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_MOVIE: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_EPISODE: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_SEASON: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_SHOW: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_CLIP: KODI_TYPE_VIDEO,
|
|
|
|
PLEX_TYPE_ARTIST: KODI_TYPE_AUDIO,
|
|
|
|
PLEX_TYPE_ALBUM: KODI_TYPE_AUDIO,
|
|
|
|
PLEX_TYPE_SONG: KODI_TYPE_AUDIO,
|
2017-03-09 02:21:00 +11:00
|
|
|
PLEX_TYPE_AUDIO: KODI_TYPE_AUDIO,
|
2017-03-09 03:06:30 +11:00
|
|
|
PLEX_TYPE_PHOTO: KODI_TYPE_PHOTO
|
2017-01-25 02:04:42 +11:00
|
|
|
}
|
|
|
|
|
2017-12-11 05:01:22 +11:00
|
|
|
KODI_PLAYLIST_TYPE_FROM_KODI_TYPE = {
|
|
|
|
KODI_TYPE_VIDEO: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_MOVIE: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_EPISODE: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_SEASON: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_SHOW: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_CLIP: KODI_TYPE_VIDEO,
|
|
|
|
KODI_TYPE_ARTIST: KODI_TYPE_AUDIO,
|
|
|
|
KODI_TYPE_ALBUM: KODI_TYPE_AUDIO,
|
|
|
|
KODI_TYPE_SONG: KODI_TYPE_AUDIO,
|
|
|
|
KODI_TYPE_AUDIO: KODI_TYPE_AUDIO,
|
|
|
|
KODI_TYPE_PHOTO: KODI_TYPE_PHOTO
|
|
|
|
}
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
REMAP_TYPE_FROM_PLEXTYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 'movie',
|
|
|
|
PLEX_TYPE_CLIP: 'clip',
|
|
|
|
PLEX_TYPE_SHOW: 'tv',
|
|
|
|
PLEX_TYPE_SEASON: 'tv',
|
|
|
|
PLEX_TYPE_EPISODE: 'tv',
|
|
|
|
PLEX_TYPE_ARTIST: 'music',
|
|
|
|
PLEX_TYPE_ALBUM: 'music',
|
|
|
|
PLEX_TYPE_SONG: 'music',
|
|
|
|
PLEX_TYPE_PHOTO: 'photo'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-09 04:00:54 +11:00
|
|
|
ICON_FROM_PLEXTYPE = {
|
|
|
|
PLEX_TYPE_VIDEO: 'DefaultAddonAlbumInfo.png',
|
|
|
|
PLEX_TYPE_MOVIE: 'DefaultMovies.png',
|
|
|
|
PLEX_TYPE_EPISODE: 'DefaultTvShows.png',
|
|
|
|
PLEX_TYPE_SEASON: 'DefaultTvShows.png',
|
|
|
|
PLEX_TYPE_SHOW: 'DefaultTvShows.png',
|
|
|
|
PLEX_TYPE_CLIP: 'DefaultAddonAlbumInfo.png',
|
|
|
|
PLEX_TYPE_ARTIST: 'DefaultArtist.png',
|
|
|
|
PLEX_TYPE_ALBUM: 'DefaultAlbumCover.png',
|
|
|
|
PLEX_TYPE_SONG: 'DefaultMusicSongs.png',
|
|
|
|
PLEX_TYPE_AUDIO: 'DefaultAddonAlbumInfo.png',
|
|
|
|
PLEX_TYPE_PHOTO: 'DefaultPicture.png',
|
|
|
|
PLEX_TYPE_PLAYLIST: 'DefaultPlaylist.png',
|
|
|
|
'mixed': 'DefaultAddonAlbumInfo.png'
|
|
|
|
}
|
|
|
|
|
2018-11-10 01:05:17 +11:00
|
|
|
TRANSLATION_FROM_PLEXTYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 342,
|
|
|
|
PLEX_TYPE_EPISODE: 20360,
|
|
|
|
PLEX_TYPE_SEASON: 20373,
|
|
|
|
PLEX_TYPE_SHOW: 20343,
|
|
|
|
PLEX_TYPE_SONG: 134,
|
|
|
|
PLEX_TYPE_ARTIST: 133,
|
|
|
|
PLEX_TYPE_ALBUM: 132,
|
|
|
|
PLEX_TYPE_PHOTO: 1,
|
|
|
|
}
|
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
REMAP_TYPE_FROM_PLEXTYPE = {
|
|
|
|
'movie': 'movie',
|
|
|
|
'show': 'tv',
|
|
|
|
'season': 'tv',
|
|
|
|
'episode': 'tv',
|
|
|
|
'artist': 'music',
|
|
|
|
'album': 'music',
|
|
|
|
'song': 'music',
|
|
|
|
'track': 'music',
|
|
|
|
'clip': 'clip',
|
|
|
|
'photo': 'photo'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-02 22:27:21 +11:00
|
|
|
PLEX_TYPE_FROM_WEBSOCKET = {
|
|
|
|
1: PLEX_TYPE_MOVIE,
|
|
|
|
2: PLEX_TYPE_SHOW,
|
|
|
|
3: PLEX_TYPE_SEASON,
|
|
|
|
4: PLEX_TYPE_EPISODE,
|
|
|
|
8: PLEX_TYPE_ARTIST,
|
|
|
|
9: PLEX_TYPE_ALBUM,
|
|
|
|
10: PLEX_TYPE_SONG,
|
2018-05-03 01:27:35 +10:00
|
|
|
12: PLEX_TYPE_CLIP,
|
2018-12-02 23:19:13 +11:00
|
|
|
15: 'playlist',
|
|
|
|
18: PLEX_TYPE_SET
|
2017-02-02 22:27:21 +11:00
|
|
|
}
|
|
|
|
|
2018-10-22 01:56:13 +11:00
|
|
|
PLEX_TYPE_NUMBER_FROM_PLEX_TYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 1,
|
|
|
|
PLEX_TYPE_SHOW: 2,
|
|
|
|
PLEX_TYPE_SEASON: 3,
|
|
|
|
PLEX_TYPE_EPISODE: 4,
|
|
|
|
PLEX_TYPE_ARTIST: 8,
|
|
|
|
PLEX_TYPE_ALBUM: 9,
|
|
|
|
PLEX_TYPE_SONG: 10,
|
|
|
|
PLEX_TYPE_CLIP: 12,
|
2018-12-02 23:19:13 +11:00
|
|
|
'playlist': 15,
|
|
|
|
PLEX_TYPE_SET: 18
|
2018-10-22 01:56:13 +11:00
|
|
|
}
|
|
|
|
|
2017-02-02 22:27:21 +11:00
|
|
|
|
2019-01-09 04:00:54 +11:00
|
|
|
# To be used with e.g. Kodi Widgets
|
|
|
|
MEDIATYPE_FROM_PLEX_TYPE = {
|
|
|
|
PLEX_TYPE_MOVIE: 'movies',
|
|
|
|
PLEX_TYPE_SHOW: 'tvshows',
|
|
|
|
PLEX_TYPE_SEASON: 'tvshows',
|
|
|
|
PLEX_TYPE_EPISODE: 'episodes',
|
|
|
|
PLEX_TYPE_ARTIST: 'artists',
|
|
|
|
PLEX_TYPE_ALBUM: 'albumbs',
|
|
|
|
PLEX_TYPE_SONG: 'songs',
|
|
|
|
PLEX_TYPE_CLIP: 'videos',
|
|
|
|
PLEX_TYPE_SET: 'movies',
|
|
|
|
PLEX_TYPE_PHOTO: 'photos',
|
|
|
|
'mixed': 'tvshows',
|
|
|
|
}
|
|
|
|
|
2018-03-04 00:40:12 +11:00
|
|
|
KODI_TO_PLEX_ARTWORK = {
|
|
|
|
'poster': 'thumb',
|
|
|
|
'banner': 'banner',
|
2018-03-04 23:39:18 +11:00
|
|
|
'fanart': 'art'
|
2018-03-04 00:40:12 +11:00
|
|
|
}
|
|
|
|
|
2018-04-20 23:58:35 +10:00
|
|
|
KODI_TO_PLEX_ARTWORK_EPISODE = {
|
2019-01-09 04:00:54 +11:00
|
|
|
'season.poster': 'parentThumb',
|
|
|
|
'tvshow.poster': 'grandparentThumb',
|
|
|
|
'tvshow.fanart': 'grandparentArt',
|
|
|
|
# 'tvshow.banner': 'banner' # Not included in PMS episode metadata
|
2018-04-20 23:58:35 +10:00
|
|
|
}
|
|
|
|
|
2018-03-04 23:39:18 +11:00
|
|
|
# Might be implemented in the future: 'icon', 'landscape' (16:9)
|
|
|
|
ALL_KODI_ARTWORK = (
|
|
|
|
'thumb',
|
|
|
|
'poster',
|
|
|
|
'banner',
|
|
|
|
'clearart',
|
|
|
|
'clearlogo',
|
|
|
|
'fanart',
|
|
|
|
'discart'
|
|
|
|
)
|
|
|
|
|
|
|
|
# we need to use a little mapping between fanart.tv arttypes and kodi artttypes
|
|
|
|
FANART_TV_TO_KODI_TYPE = [
|
|
|
|
('poster', 'poster'),
|
|
|
|
('logo', 'clearlogo'),
|
|
|
|
('musiclogo', 'clearlogo'),
|
|
|
|
('disc', 'discart'),
|
|
|
|
('clearart', 'clearart'),
|
|
|
|
('banner', 'banner'),
|
|
|
|
('clearlogo', 'clearlogo'),
|
|
|
|
('background', 'fanart'),
|
|
|
|
('showbackground', 'fanart'),
|
|
|
|
('characterart', 'characterart')
|
|
|
|
]
|
|
|
|
# How many different backgrounds do we want to load from fanart.tv?
|
|
|
|
MAX_BACKGROUND_COUNT = 10
|
|
|
|
|
2018-03-04 00:40:12 +11:00
|
|
|
|
2017-01-25 02:04:42 +11:00
|
|
|
# extensions from:
|
|
|
|
# http://kodi.wiki/view/Features_and_supported_codecs#Format_support (RAW image
|
|
|
|
# formats, BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX and Targa/TGA)
|
|
|
|
KODI_SUPPORTED_IMAGES = (
|
|
|
|
'.bmp',
|
|
|
|
'.jpg',
|
|
|
|
'.jpeg',
|
|
|
|
'.gif',
|
|
|
|
'.png',
|
|
|
|
'.tiff',
|
|
|
|
'.mng',
|
|
|
|
'.ico',
|
|
|
|
'.pcx',
|
|
|
|
'.tga'
|
|
|
|
)
|
2017-03-05 03:54:24 +11:00
|
|
|
|
|
|
|
|
|
|
|
# Translation table from Alexa websocket commands to Plex Companion
|
|
|
|
ALEXA_TO_COMPANION = {
|
|
|
|
'queryKey': 'key',
|
|
|
|
'queryOffset': 'offset',
|
|
|
|
'queryMachineIdentifier': 'machineIdentifier',
|
|
|
|
'queryProtocol': 'protocol',
|
|
|
|
'queryAddress': 'address',
|
|
|
|
'queryPort': 'port',
|
|
|
|
'queryContainerKey': 'containerKey',
|
|
|
|
'queryToken': 'token',
|
|
|
|
}
|
2017-03-09 02:21:00 +11:00
|
|
|
|
|
|
|
# Kodi sort methods for xbmcplugin.addSortMethod()
|
|
|
|
SORT_METHODS_DIRECTORY = (
|
|
|
|
'SORT_METHOD_UNSORTED', # sorted as returned from Plex
|
|
|
|
'SORT_METHOD_LABEL',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_PHOTOS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_LABEL',
|
|
|
|
'SORT_METHOD_DATE',
|
|
|
|
'SORT_METHOD_DATEADDED',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_CLIPS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
|
|
|
'SORT_METHOD_DURATION',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_MOVIES = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
2017-04-14 22:45:39 +10:00
|
|
|
'SORT_METHOD_DATEADDED',
|
|
|
|
'SORT_METHOD_GENRE',
|
2017-03-09 02:21:00 +11:00
|
|
|
'SORT_METHOD_VIDEO_RATING',
|
|
|
|
'SORT_METHOD_VIDEO_USER_RATING',
|
|
|
|
'SORT_METHOD_MPAA_RATING',
|
2017-04-14 22:45:39 +10:00
|
|
|
'SORT_METHOD_DURATION',
|
2017-03-09 02:21:00 +11:00
|
|
|
'SORT_METHOD_COUNTRY',
|
|
|
|
'SORT_METHOD_STUDIO',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHOD_TVSHOWS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
2017-04-14 22:56:04 +10:00
|
|
|
'SORT_METHOD_DATEADDED',
|
2017-03-09 02:21:00 +11:00
|
|
|
'SORT_METHOD_VIDEO_RATING',
|
|
|
|
'SORT_METHOD_VIDEO_USER_RATING',
|
|
|
|
'SORT_METHOD_MPAA_RATING',
|
|
|
|
'SORT_METHOD_COUNTRY',
|
|
|
|
'SORT_METHOD_GENRE',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_EPISODES = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
2017-03-09 03:02:26 +11:00
|
|
|
'SORT_METHOD_EPISODE',
|
2017-04-14 22:56:04 +10:00
|
|
|
'SORT_METHOD_DATEADDED',
|
2017-03-09 02:21:00 +11:00
|
|
|
'SORT_METHOD_VIDEO_RATING',
|
|
|
|
'SORT_METHOD_VIDEO_USER_RATING',
|
|
|
|
'SORT_METHOD_MPAA_RATING',
|
2017-04-14 22:56:04 +10:00
|
|
|
'SORT_METHOD_DURATION',
|
2017-03-09 03:02:26 +11:00
|
|
|
'SORT_METHOD_FILE',
|
|
|
|
'SORT_METHOD_FULLPATH',
|
2017-03-09 02:21:00 +11:00
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_SONGS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
|
|
|
'SORT_METHOD_TRACKNUM',
|
|
|
|
'SORT_METHOD_DURATION',
|
|
|
|
'SORT_METHOD_ARTIST',
|
|
|
|
'SORT_METHOD_ALBUM',
|
|
|
|
'SORT_METHOD_SONG_RATING',
|
|
|
|
'SORT_METHOD_SONG_USER_RATING'
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_ARTISTS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
|
|
|
'SORT_METHOD_TRACKNUM',
|
|
|
|
'SORT_METHOD_DURATION',
|
|
|
|
'SORT_METHOD_ARTIST',
|
|
|
|
'SORT_METHOD_ALBUM',
|
|
|
|
)
|
|
|
|
|
|
|
|
SORT_METHODS_ALBUMS = (
|
|
|
|
'SORT_METHOD_UNSORTED',
|
|
|
|
'SORT_METHOD_TITLE',
|
|
|
|
'SORT_METHOD_TRACKNUM',
|
|
|
|
'SORT_METHOD_DURATION',
|
|
|
|
'SORT_METHOD_ARTIST',
|
|
|
|
'SORT_METHOD_ALBUM',
|
|
|
|
)
|
2017-12-09 23:47:19 +11:00
|
|
|
|
|
|
|
|
|
|
|
XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
|
|
|
|
|
|
COMPANION_OK_MESSAGE = XML_HEADER + '<Response code="200" status="OK" />'
|
2017-12-11 05:01:22 +11:00
|
|
|
|
|
|
|
PLEX_REPEAT_FROM_KODI_REPEAT = {
|
|
|
|
'off': '0',
|
|
|
|
'one': '1',
|
|
|
|
'all': '2' # does this work?!?
|
|
|
|
}
|
2017-12-14 20:22:48 +11:00
|
|
|
|
|
|
|
# Stream in PMS xml contains a streamType to distinguish the kind of stream
|
|
|
|
PLEX_STREAM_TYPE_FROM_STREAM_TYPE = {
|
|
|
|
'video': '1',
|
|
|
|
'audio': '2',
|
|
|
|
'subtitle': '3'
|
|
|
|
}
|
2018-06-24 02:25:18 +10:00
|
|
|
|
|
|
|
# Encoding to be used for our m3u playlist files
|
|
|
|
# m3u files do not have encoding specified by definition, unfortunately.
|
2019-02-06 04:52:10 +11:00
|
|
|
if DEVICE == 'Windows':
|
2018-06-24 02:25:18 +10:00
|
|
|
M3U_ENCODING = 'mbcs'
|
|
|
|
else:
|
|
|
|
M3U_ENCODING = sys.getfilesystemencoding()
|
|
|
|
if (not M3U_ENCODING or
|
|
|
|
M3U_ENCODING == 'ascii' or
|
|
|
|
M3U_ENCODING == 'ANSI_X3.4-1968'):
|
|
|
|
M3U_ENCODING = 'utf-8'
|
2019-02-24 21:18:48 +11:00
|
|
|
|
|
|
|
|
|
|
|
def database_paths():
|
|
|
|
'''
|
|
|
|
Set the Kodi database paths - PKC will choose the HIGHEST available and
|
|
|
|
supported database version for the current Kodi version.
|
|
|
|
Will raise a RuntimeError if the DBs are not found or of a wrong,
|
|
|
|
unsupported version
|
|
|
|
'''
|
|
|
|
# Check Kodi version first
|
|
|
|
if KODIVERSION not in (17, 18, 19):
|
|
|
|
raise RuntimeError('Kodiversion %s not supported by PKC' % KODIVERSION)
|
|
|
|
|
|
|
|
database_path = try_decode(xbmc.translatePath('special://database'))
|
|
|
|
thismodule = sys.modules[__name__]
|
|
|
|
types = (('MyVideos%s.db', SUPPORTED_VIDEO_DB,
|
|
|
|
'DB_VIDEO_VERSION', 'DB_VIDEO_PATH'),
|
|
|
|
('MyMusic%s.db', SUPPORTED_MUSIC_DB,
|
|
|
|
'DB_MUSIC_VERSION', 'DB_MUSIC_PATH'),
|
|
|
|
('Textures%s.db', SUPPORTED_TEXTURE_DB,
|
|
|
|
'DB_TEXTURE_VERSION', 'DB_TEXTURE_PATH'))
|
|
|
|
for string, versions, actual_version, actual_path in types:
|
|
|
|
for version in versions[KODIVERSION]:
|
|
|
|
file = string % version
|
|
|
|
path = path_ops.path.join(database_path, file)
|
|
|
|
if path_ops.exists(path):
|
|
|
|
setattr(thismodule, actual_version, version)
|
|
|
|
setattr(thismodule, actual_path, path)
|
2019-02-27 03:41:35 +11:00
|
|
|
break
|
2019-02-24 21:18:48 +11:00
|
|
|
|
|
|
|
if (DB_VIDEO_VERSION is None or
|
|
|
|
DB_MUSIC_VERSION is None or
|
|
|
|
DB_TEXTURE_VERSION is None):
|
|
|
|
raise RuntimeError('Kodi database versions not supported by PKC')
|