Merge branch 'develop' into translations
This commit is contained in:
commit
4cbb1dc7bc
21 changed files with 226 additions and 108 deletions
|
@ -1,5 +1,5 @@
|
|||
[![stable version](https://img.shields.io/badge/stable_version-1.7.7-blue.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect/bin/repository.plexkodiconnect/repository.plexkodiconnect-1.0.0.zip)
|
||||
[![beta version](https://img.shields.io/badge/beta_version-1.7.12-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
|
||||
[![beta version](https://img.shields.io/badge/beta_version-1.7.17-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
|
||||
|
||||
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
||||
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||
|
|
29
addon.xml
29
addon.xml
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.7.12" provider-name="croneter">
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.7.17" provider-name="croneter">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.1.0"/>
|
||||
<import addon="script.module.requests" version="2.3.0" />
|
||||
|
@ -44,7 +44,32 @@
|
|||
<disclaimer lang="nl_NL">Gebruik op eigen risico</disclaimer>
|
||||
<disclaimer lang="zh_TW">使用風險由您自己承擔</disclaimer>
|
||||
<disclaimer lang="es_ES">Usar a su propio riesgo</disclaimer>
|
||||
<news>version 1.7.12 (beta only)
|
||||
<news>version 1.7.17 (beta only)
|
||||
- Don't add media by other add-ons to queue
|
||||
- Fix KeyError for Plex Companion
|
||||
- Repace Kodi mkdirs with os.makedirs
|
||||
- Use xbmcvfs exists instead of os.path.exists
|
||||
|
||||
version 1.7.16 (beta only)
|
||||
- Fix PKC complaining about files not found
|
||||
- Fix multiple subtitles per language not showing
|
||||
- Update Czech translation
|
||||
- Fix too many arguments when marking 100% watched
|
||||
- More small fixes
|
||||
|
||||
version 1.7.15 (beta only)
|
||||
- Fix companion for "Playback via PMS"
|
||||
- Change sleeping behavior for playqueue client
|
||||
- Plex Companion: add itemType to playstate
|
||||
- Less logging
|
||||
|
||||
version 1.7.14 (beta only)
|
||||
- Fix TypeError, but for real now
|
||||
|
||||
version 1.7.13 (beta only)
|
||||
- Fix TypeError with AdvancedSettings.xml missing
|
||||
|
||||
version 1.7.12 (beta only)
|
||||
- Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database
|
||||
- Some Plex Companion fixes
|
||||
- Fix UnicodeDecodeError on user switch
|
||||
|
|
|
@ -1,3 +1,28 @@
|
|||
version 1.7.17 (beta only)
|
||||
- Don't add media by other add-ons to queue
|
||||
- Fix KeyError for Plex Companion
|
||||
- Repace Kodi mkdirs with os.makedirs
|
||||
- Use xbmcvfs exists instead of os.path.exists
|
||||
|
||||
version 1.7.16 (beta only)
|
||||
- Fix PKC complaining about files not found
|
||||
- Fix multiple subtitles per language not showing
|
||||
- Update Czech translation
|
||||
- Fix too many arguments when marking 100% watched
|
||||
- More small fixes
|
||||
|
||||
version 1.7.15 (beta only)
|
||||
- Fix companion for "Playback via PMS"
|
||||
- Change sleeping behavior for playqueue client
|
||||
- Plex Companion: add itemType to playstate
|
||||
- Less logging
|
||||
|
||||
version 1.7.14 (beta only)
|
||||
- Fix TypeError, but for real now
|
||||
|
||||
version 1.7.13 (beta only)
|
||||
- Fix TypeError with AdvancedSettings.xml missing
|
||||
|
||||
version 1.7.12 (beta only)
|
||||
- Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database
|
||||
- Some Plex Companion fixes
|
||||
|
|
|
@ -1899,3 +1899,23 @@ msgstr ""
|
|||
msgctxt "#39711"
|
||||
msgid "New Plex music library detected. Sorry, but we need to restart Kodi now due to the changes made."
|
||||
msgstr ""
|
||||
|
||||
# Shown during sync process
|
||||
msgctxt "#39712"
|
||||
msgid "downloaded"
|
||||
msgstr ""
|
||||
|
||||
# Shown during sync process
|
||||
msgctxt "#39713"
|
||||
msgid "processed"
|
||||
msgstr ""
|
||||
|
||||
# Shown during sync process
|
||||
msgctxt "#39714"
|
||||
msgid "Sync"
|
||||
msgstr ""
|
||||
|
||||
# Shown during sync process
|
||||
msgctxt "#39715"
|
||||
msgid "items"
|
||||
msgstr ""
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###############################################################################
|
||||
import logging
|
||||
|
||||
from xbmcgui import ListItem
|
||||
|
||||
###############################################################################
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
def convert_PKC_to_listitem(PKC_listitem):
|
||||
"""
|
||||
Insert a PKC_listitem and you will receive a valid XBMC listitem
|
||||
"""
|
||||
data = PKC_listitem.data
|
||||
log.debug('data is: %s' % data)
|
||||
listitem = ListItem(label=data.get('label'),
|
||||
label2=data.get('label2'),
|
||||
path=data.get('path'))
|
||||
|
|
|
@ -39,16 +39,17 @@ import xml.etree.ElementTree as etree
|
|||
from re import compile as re_compile, sub
|
||||
from json import dumps
|
||||
from urllib import urlencode, quote_plus, unquote
|
||||
from os.path import basename, join, exists
|
||||
from os.path import basename, join
|
||||
from os import makedirs
|
||||
|
||||
import xbmcgui
|
||||
from xbmc import sleep, executebuiltin
|
||||
from xbmcvfs import exists
|
||||
|
||||
import clientinfo as client
|
||||
from downloadutils import DownloadUtils
|
||||
from utils import window, settings, language as lang, tryDecode, tryEncode, \
|
||||
DateToKodi
|
||||
DateToKodi, exists_dir
|
||||
from PlexFunctions import PMSHttpsEnabled
|
||||
import plexdb_functions as plexdb
|
||||
import variables as v
|
||||
|
@ -2117,10 +2118,9 @@ class API():
|
|||
continue
|
||||
if fanartcount > maxfanarts:
|
||||
break
|
||||
if exists(tryEncode(entry['url'])):
|
||||
allartworks['Backdrop'].append(
|
||||
entry['url'].replace(' ', '%20'))
|
||||
fanartcount += 1
|
||||
allartworks['Backdrop'].append(
|
||||
entry['url'].replace(' ', '%20'))
|
||||
fanartcount += 1
|
||||
return allartworks
|
||||
|
||||
def getSetArtwork(self, parentInfo=False):
|
||||
|
@ -2303,6 +2303,7 @@ class API():
|
|||
except (TypeError, KeyError, IndexError):
|
||||
return
|
||||
kodiindex = 0
|
||||
fileindex = 0
|
||||
for stream in mediastreams:
|
||||
# Since plex returns all possible tracks together, have to pull
|
||||
# only external subtitles - only for these a 'key' exists
|
||||
|
@ -2318,8 +2319,10 @@ class API():
|
|||
if stream.attrib.get('languageCode') is not None:
|
||||
path = self.download_external_subtitles(
|
||||
"{server}%s" % key,
|
||||
"subtitle.%s.%s" % (stream.attrib['languageCode'],
|
||||
stream.attrib['codec']))
|
||||
"subtitle%02d.%s.%s" % (fileindex,
|
||||
stream.attrib['languageCode'],
|
||||
stream.attrib['codec']))
|
||||
fileindex += 1
|
||||
# We don't know the language - no need to download
|
||||
else:
|
||||
path = self.addPlexCredentialsToUrl(
|
||||
|
@ -2341,7 +2344,7 @@ class API():
|
|||
|
||||
Returns the path to the downloaded subtitle or None
|
||||
"""
|
||||
if not exists(v.EXTERNAL_SUBTITLE_TEMP_PATH):
|
||||
if not exists_dir(v.EXTERNAL_SUBTITLE_TEMP_PATH):
|
||||
makedirs(v.EXTERNAL_SUBTITLE_TEMP_PATH)
|
||||
path = join(v.EXTERNAL_SUBTITLE_TEMP_PATH, filename)
|
||||
r = DownloadUtils().downloadUrl(url, return_response=True)
|
||||
|
@ -2541,16 +2544,22 @@ class API():
|
|||
# exist() needs a / or \ at the end to work for directories
|
||||
if folder is False:
|
||||
# files
|
||||
check = exists(tryEncode(path)) == 1
|
||||
check = exists(tryEncode(path))
|
||||
else:
|
||||
# directories
|
||||
if "\\" in path:
|
||||
# Add the missing backslash
|
||||
check = exists(tryEncode(path + "\\")) == 1
|
||||
if not path.endswith('\\'):
|
||||
# Add the missing backslash
|
||||
check = exists_dir(tryEncode(path + "\\"))
|
||||
else:
|
||||
check = exists_dir(tryEncode(path))
|
||||
else:
|
||||
check = exists(tryEncode(path + "/")) == 1
|
||||
if not path.endswith('/'):
|
||||
check = exists_dir(tryEncode(path + "/"))
|
||||
else:
|
||||
check = exists_dir(tryEncode(path))
|
||||
|
||||
if check is False:
|
||||
if not check:
|
||||
if forceCheck is False:
|
||||
# Validate the path is correct with user intervention
|
||||
if self.askToValidate(path):
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
import logging
|
||||
from json import dumps, loads
|
||||
import requests
|
||||
from os.path import exists
|
||||
from shutil import rmtree
|
||||
from urllib import quote_plus, unquote
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
|
||||
from xbmc import executeJSONRPC, sleep, translatePath
|
||||
from xbmcvfs import exists
|
||||
|
||||
from utils import window, settings, language as lang, kodiSQL, tryEncode, \
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, dialog
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, dialog, exists_dir
|
||||
|
||||
# Disable annoying requests warnings
|
||||
import requests.packages.urllib3
|
||||
|
@ -229,7 +229,7 @@ class Artwork():
|
|||
log.info("Resetting all cache data first")
|
||||
# Remove all existing textures first
|
||||
path = translatePath("special://thumbnails/")
|
||||
if exists(path):
|
||||
if exists_dir(path):
|
||||
rmtree(path, ignore_errors=True)
|
||||
|
||||
# remove all existing data from texture DB
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import logging
|
||||
from shutil import copyfile
|
||||
from os import walk, makedirs
|
||||
from os.path import basename, join, exists
|
||||
from os.path import basename, join
|
||||
from sys import argv
|
||||
from urllib import urlencode
|
||||
|
||||
|
@ -12,7 +12,7 @@ from xbmc import sleep, executebuiltin, translatePath
|
|||
from xbmcgui import ListItem
|
||||
|
||||
from utils import window, settings, language as lang, dialog, tryEncode, \
|
||||
CatchExceptions, JSONRPC
|
||||
CatchExceptions, JSONRPC, exists_dir
|
||||
import downloadutils
|
||||
|
||||
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
|
||||
|
@ -74,7 +74,7 @@ def togglePlexTV():
|
|||
if settings('plexToken'):
|
||||
log.info('Reseting plex.tv credentials in settings')
|
||||
settings('plexLogin', value="")
|
||||
settings('plexToken', value=""),
|
||||
settings('plexToken', value="")
|
||||
settings('plexid', value="")
|
||||
settings('plexHomeSize', value="1")
|
||||
settings('plexAvatar', value="")
|
||||
|
@ -498,7 +498,7 @@ def getVideoFiles(plexId, params):
|
|||
path = path.replace('\\', '\\\\')
|
||||
# Directory only, get rid of filename
|
||||
path = path.replace(basename(path), '')
|
||||
if exists(path):
|
||||
if exists_dir(path):
|
||||
for root, dirs, files in walk(path):
|
||||
for directory in dirs:
|
||||
item_path = join(root, directory)
|
||||
|
@ -513,6 +513,7 @@ def getVideoFiles(plexId, params):
|
|||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=file,
|
||||
listitem=li)
|
||||
break
|
||||
else:
|
||||
log.error('Kodi cannot access folder %s' % path)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
@ -536,7 +537,7 @@ def getExtraFanArt(plexid, plexPath):
|
|||
# We need to store the images locally for this to work
|
||||
# because of the caching system in xbmc
|
||||
fanartDir = translatePath("special://thumbnails/plex/%s/" % plexid)
|
||||
if not exists(fanartDir):
|
||||
if not exists_dir(fanartDir):
|
||||
# Download the images to the cache directory
|
||||
makedirs(fanartDir)
|
||||
xml = GetPlexMetadata(plexid)
|
||||
|
|
|
@ -402,11 +402,11 @@ class InitialSetup():
|
|||
|
||||
# Get current Kodi video cache setting
|
||||
cache, _ = advancedsettings_xml(['cache', 'memorysize'])
|
||||
if cache is not None:
|
||||
cache = str(cache.text)
|
||||
else:
|
||||
if cache is None:
|
||||
# Kodi default cache
|
||||
cache = '20971520'
|
||||
else:
|
||||
cache = str(cache.text)
|
||||
log.info('Current Kodi video memory cache in bytes: %s' % cache)
|
||||
settings('kodi_video_cache', value=cache)
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ class Items(object):
|
|||
'Mark item played at %s percent.'
|
||||
% (item['ratingKey'], str(complete), MARK_PLAYED_AT), 1)
|
||||
if complete >= MARK_PLAYED_AT:
|
||||
log.info('Marking as completely watched in Kodi', 1)
|
||||
log.info('Marking as completely watched in Kodi')
|
||||
sleep(500)
|
||||
try:
|
||||
item['viewCount'] += 1
|
||||
|
@ -1189,10 +1189,9 @@ class TVShows(Items):
|
|||
v.KODI_TYPE_SEASON)
|
||||
for season in seasons:
|
||||
self.removeSeason(season[1])
|
||||
else:
|
||||
# Delete plex season entries
|
||||
plex_db.removeItems_byParentId(showid,
|
||||
v.KODI_TYPE_SEASON)
|
||||
# Delete plex season entries
|
||||
plex_db.removeItems_byParentId(showid,
|
||||
v.KODI_TYPE_SEASON)
|
||||
self.removeShow(showid)
|
||||
plex_db.removeItem(show[0])
|
||||
|
||||
|
@ -1208,14 +1207,12 @@ class TVShows(Items):
|
|||
seasonid, v.KODI_TYPE_EPISODE)
|
||||
for episode in season_episodes:
|
||||
self.removeEpisode(episode[1], episode[2])
|
||||
else:
|
||||
# Remove plex episodes
|
||||
plex_db.removeItems_byParentId(seasonid,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
else:
|
||||
# Remove plex seasons
|
||||
plex_db.removeItems_byParentId(kodiid,
|
||||
v.KODI_TYPE_SEASON)
|
||||
# Remove plex episodes
|
||||
plex_db.removeItems_byParentId(seasonid,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
# Remove plex seasons
|
||||
plex_db.removeItems_byParentId(kodiid,
|
||||
v.KODI_TYPE_SEASON)
|
||||
|
||||
# Remove tvshow
|
||||
self.removeShow(kodiid)
|
||||
|
@ -1228,9 +1225,8 @@ class TVShows(Items):
|
|||
v.KODI_TYPE_EPISODE)
|
||||
for episode in season_episodes:
|
||||
self.removeEpisode(episode[1], episode[2])
|
||||
else:
|
||||
# Remove plex episodes
|
||||
plex_db.removeItems_byParentId(kodiid, v.KODI_TYPE_EPISODE)
|
||||
# Remove plex episodes
|
||||
plex_db.removeItems_byParentId(kodiid, v.KODI_TYPE_EPISODE)
|
||||
|
||||
# Remove season
|
||||
self.removeSeason(kodiid)
|
||||
|
|
|
@ -1409,9 +1409,8 @@ class Kodidb_Functions():
|
|||
ID = 'idEpisode'
|
||||
elif kodi_type == v.KODI_TYPE_SONG:
|
||||
ID = 'idSong'
|
||||
query = ('''UPDATE %s SET userrating = ? WHERE %s = ?'''
|
||||
% (kodi_type, ID))
|
||||
self.cursor.execute(query, (userrating, kodi_id))
|
||||
query = '''UPDATE ? SET userrating = ? WHERE ? = ?'''
|
||||
self.cursor.execute(query, (kodi_type, userrating, ID, kodi_id))
|
||||
|
||||
def create_entry_uniqueid(self):
|
||||
self.cursor.execute(
|
||||
|
|
|
@ -54,9 +54,8 @@ class Threaded_Show_Sync_Info(Thread):
|
|||
total = self.total
|
||||
dialog = self.dialog
|
||||
threadStopped = self.threadStopped
|
||||
dialog.create("%s: Sync %s: %s items"
|
||||
% (lang(29999), self.item_type, str(total)),
|
||||
"Starting")
|
||||
dialog.create("%s %s: %s %s"
|
||||
% (lang(39714), self.item_type, str(total), lang(39715)))
|
||||
|
||||
total = 2 * total
|
||||
totalProgress = 0
|
||||
|
@ -71,9 +70,11 @@ class Threaded_Show_Sync_Info(Thread):
|
|||
except ZeroDivisionError:
|
||||
percentage = 0
|
||||
dialog.update(percentage,
|
||||
message="%s downloaded. %s processed: %s"
|
||||
message="%s %s. %s %s: %s"
|
||||
% (get_progress,
|
||||
lang(39712),
|
||||
process_progress,
|
||||
lang(39713),
|
||||
viewName))
|
||||
# Sleep for x milliseconds
|
||||
sleep(200)
|
||||
|
|
|
@ -4,10 +4,10 @@ import logging
|
|||
from threading import Thread
|
||||
import Queue
|
||||
from random import shuffle
|
||||
from os.path import exists
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from xbmcvfs import exists
|
||||
|
||||
from utils import window, settings, getUnixTimestamp, sourcesXML,\
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, LogTime, getScreensaver,\
|
||||
|
@ -297,15 +297,6 @@ class LibrarySync(Thread):
|
|||
}
|
||||
if self.enableMusic:
|
||||
process['music'] = self.PlexMusic
|
||||
if self.direct_paths is True:
|
||||
if music.set_excludefromscan_music_folders() is True:
|
||||
log.info('Detected new Music library - restarting now')
|
||||
# 'New Plex music library detected. Sorry, but we need to
|
||||
# restart Kodi now due to the changes made.'
|
||||
dialog('ok', lang(29999), lang(39711))
|
||||
from xbmc import executebuiltin
|
||||
executebuiltin('RestartApp')
|
||||
return False
|
||||
|
||||
# Do the processing
|
||||
for itemtype in process:
|
||||
|
@ -483,6 +474,16 @@ class LibrarySync(Thread):
|
|||
"""
|
||||
Compare the views to Plex
|
||||
"""
|
||||
if self.direct_paths is True:
|
||||
if music.set_excludefromscan_music_folders() is True:
|
||||
log.info('Detected new Music library - restarting now')
|
||||
# 'New Plex music library detected. Sorry, but we need to
|
||||
# restart Kodi now due to the changes made.'
|
||||
dialog('ok', lang(29999), lang(39711))
|
||||
from xbmc import executebuiltin
|
||||
executebuiltin('RestartApp')
|
||||
return False
|
||||
|
||||
self.views = []
|
||||
vnodes = self.vnodes
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ class PlaybackUtils():
|
|||
playqueue,
|
||||
self.currentPosition+1,
|
||||
convert_PKC_to_listitem(listitem),
|
||||
playurl,
|
||||
file=playurl,
|
||||
kodi_item={'id': kodi_id, 'type': kodi_type})
|
||||
else:
|
||||
# Full metadata$
|
||||
|
|
|
@ -75,6 +75,7 @@ class Playqueue_Object(Playlist_Object_Baseclase):
|
|||
class Playlist_Item(object):
|
||||
ID = None # Plex playlist/playqueue id, e.g. playQueueItemID
|
||||
plex_id = None # Plex unique item id, "ratingKey"
|
||||
plex_type = None # Plex type, e.g. 'movie', 'clip'
|
||||
plex_UUID = None # Plex librarySectionUUID
|
||||
kodi_id = None # Kodi unique kodi id (unique only within type!)
|
||||
kodi_type = None # Kodi type: 'movie'
|
||||
|
@ -102,20 +103,22 @@ def playlist_item_from_kodi(kodi_item):
|
|||
"""
|
||||
item = Playlist_Item()
|
||||
item.kodi_id = kodi_item.get('id')
|
||||
item.kodi_type = kodi_item.get('type')
|
||||
if item.kodi_id:
|
||||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
plex_dbitem = plex_db.getItem_byKodiId(kodi_item['id'],
|
||||
kodi_item['type'])
|
||||
try:
|
||||
item.plex_id = plex_dbitem[0]
|
||||
item.plex_type = plex_dbitem[2]
|
||||
item.plex_UUID = plex_dbitem[0] # we dont need the uuid yet :-)
|
||||
except TypeError:
|
||||
pass
|
||||
item.file = kodi_item.get('file')
|
||||
if item.file is not None and item.plex_id is None:
|
||||
item.plex_id = dict(
|
||||
parse_qsl(urlsplit(item.file).query)).get('plex_id')
|
||||
item.kodi_type = kodi_item.get('type')
|
||||
if item.plex_id is None and item.file is not None:
|
||||
query = dict(parse_qsl(urlsplit(item.file).query))
|
||||
item.plex_id = query.get('plex_id')
|
||||
item.plex_type = query.get('itemType')
|
||||
if item.plex_id is None:
|
||||
item.uri = 'library://whatever/item/%s' % quote(item.file, safe='')
|
||||
else:
|
||||
|
@ -137,13 +140,14 @@ def playlist_item_from_plex(plex_id):
|
|||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
plex_dbitem = plex_db.getItem_byId(plex_id)
|
||||
try:
|
||||
item.plex_type = plex_dbitem[5]
|
||||
item.kodi_id = plex_dbitem[0]
|
||||
item.kodi_type = plex_dbitem[4]
|
||||
except:
|
||||
raise KeyError('Could not find plex_id %s in database' % plex_id)
|
||||
item.plex_UUID = plex_id
|
||||
item.uri = ('library://%s/item/library%%2Fmetadata%%2F%s' %
|
||||
(item.plex_UUID, plex_id))
|
||||
(item.plex_UUID, plex_id))
|
||||
log.debug('Made playlist item from plex: %s' % item)
|
||||
return item
|
||||
|
||||
|
@ -155,6 +159,7 @@ def playlist_item_from_xml(playlist, xml_video_element):
|
|||
item = Playlist_Item()
|
||||
api = API(xml_video_element)
|
||||
item.plex_id = api.getRatingKey()
|
||||
item.plex_type = api.getType()
|
||||
item.ID = xml_video_element.attrib['%sItemID' % playlist.kind]
|
||||
item.guid = xml_video_element.attrib.get('guid')
|
||||
if item.guid is not None:
|
||||
|
@ -314,8 +319,6 @@ def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None):
|
|||
|
||||
WILL ALSO UPDATE OUR PLAYLISTS
|
||||
"""
|
||||
log.debug('Adding new item plex_id: %s, kodi_item: %s on the Plex side at '
|
||||
'position %s for %s' % (plex_id, kodi_item, pos, playlist))
|
||||
if plex_id:
|
||||
try:
|
||||
item = playlist_item_from_plex(plex_id)
|
||||
|
@ -532,9 +535,10 @@ def add_listitem_to_Kodi_playlist(playlist, pos, listitem, file,
|
|||
# We need to add this to our internal queue as well
|
||||
if xml_video_element is not None:
|
||||
item = playlist_item_from_xml(playlist, xml_video_element)
|
||||
item.file = file
|
||||
else:
|
||||
item = playlist_item_from_kodi(kodi_item)
|
||||
if file is not None:
|
||||
item.file = file
|
||||
playlist.items.insert(pos, item)
|
||||
log.debug('Done inserting for %s' % playlist)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
|
||||
# Lock used for playqueue manipulations
|
||||
lock = RLock()
|
||||
PLUGIN = 'plugin://%s' % v.ADDON_ID
|
||||
###############################################################################
|
||||
|
||||
|
||||
|
@ -147,11 +148,19 @@ class Playqueue(Thread):
|
|||
log.debug('Comparing new Kodi playqueue %s with our play queue %s'
|
||||
% (new, old))
|
||||
for i, new_item in enumerate(new):
|
||||
if (new_item['file'].startswith('plugin://') and
|
||||
not new_item['file'].startswith(PLUGIN)):
|
||||
# Ignore new media added by other addons
|
||||
continue
|
||||
for j, old_item in enumerate(old):
|
||||
if self.threadStopped():
|
||||
# Chances are that we got an empty Kodi playlist due to
|
||||
# Kodi exit
|
||||
return
|
||||
if (old_item['file'].startswith('plugin://') and
|
||||
not old_item['file'].startswith(PLUGIN)):
|
||||
# Ignore media by other addons
|
||||
continue
|
||||
if new_item.get('id') is None:
|
||||
identical = old_item.file == new_item['file']
|
||||
else:
|
||||
|
@ -206,5 +215,9 @@ class Playqueue(Thread):
|
|||
# compare old and new playqueue
|
||||
self._compare_playqueues(playqueue, kodi_playqueue)
|
||||
playqueue.old_kodi_pl = list(kodi_playqueue)
|
||||
sleep(50)
|
||||
# Still sleep a bit so Kodi does not become
|
||||
# unresponsive
|
||||
sleep(10)
|
||||
continue
|
||||
sleep(200)
|
||||
log.info("----===## PlayQueue client stopped ##===----")
|
||||
|
|
|
@ -122,9 +122,11 @@ class SubscriptionManager:
|
|||
ret += ' shuffle="%s"' % info['shuffle']
|
||||
ret += ' mute="%s"' % self.mute
|
||||
ret += ' repeat="%s"' % info['repeat']
|
||||
ret += ' itemType="%s"' % info['itemType']
|
||||
# Might need an update in the future
|
||||
ret += ' subtitleStreamID="-1"'
|
||||
ret += ' audioStreamID="-1"'
|
||||
if ptype == 'video':
|
||||
ret += ' subtitleStreamID="-1"'
|
||||
ret += ' audioStreamID="-1"'
|
||||
|
||||
ret += '/>'
|
||||
return ret
|
||||
|
@ -225,7 +227,8 @@ class SubscriptionManager:
|
|||
props = self.js.jsonrpc(
|
||||
"Player.GetProperties",
|
||||
{"playerid": playerid,
|
||||
"properties": ["time",
|
||||
"properties": ["type",
|
||||
"time",
|
||||
"totaltime",
|
||||
"speed",
|
||||
"shuffled",
|
||||
|
@ -244,12 +247,13 @@ class SubscriptionManager:
|
|||
{"playerid": playerid,
|
||||
"properties": ["position"]})['position']
|
||||
try:
|
||||
info['playQueueItemID'] = playqueue.items[pos].ID
|
||||
info['guid'] = playqueue.items[pos].guid
|
||||
info['playQueueID'] = playqueue.ID
|
||||
info['playQueueVersion'] = playqueue.version
|
||||
info['playQueueItemID'] = playqueue.items[pos].ID or 'null'
|
||||
info['guid'] = playqueue.items[pos].guid or 'null'
|
||||
info['playQueueID'] = playqueue.ID or 'null'
|
||||
info['playQueueVersion'] = playqueue.version or 'null'
|
||||
info['itemType'] = playqueue.items[pos].plex_type or 'null'
|
||||
except:
|
||||
pass
|
||||
info['itemType'] = props.get('type') or 'null'
|
||||
except:
|
||||
import traceback
|
||||
log.error("Traceback:\n%s" % traceback.format_exc())
|
||||
|
|
|
@ -258,10 +258,11 @@ class Plex_DB_Functions():
|
|||
|
||||
def getItem_byKodiId(self, kodi_id, kodi_type):
|
||||
"""
|
||||
Returns the tuple (plex_id, parent_id) for kodi_id and kodi_type
|
||||
Returns the tuple (plex_id, parent_id, plex_type) for kodi_id and
|
||||
kodi_type
|
||||
"""
|
||||
query = '''
|
||||
SELECT plex_id, parent_id
|
||||
SELECT plex_id, parent_id, plex_type
|
||||
FROM plex
|
||||
WHERE kodi_id = ?
|
||||
AND kodi_type = ?
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
###############################################################################
|
||||
import logging
|
||||
import threading
|
||||
from os.path import exists
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
from xbmcvfs import exists
|
||||
|
||||
|
||||
from utils import window, settings, language as lang, ThreadMethods, \
|
||||
|
@ -211,10 +211,9 @@ class UserClient(threading.Thread):
|
|||
|
||||
# Get /profile/addon_data
|
||||
addondir = xbmc.translatePath(self.addon.getAddonInfo('profile'))
|
||||
hasSettings = exists("%ssettings.xml" % addondir)
|
||||
|
||||
# If there's no settings.xml
|
||||
if not hasSettings:
|
||||
if not exists("%ssettings.xml" % addondir):
|
||||
log.error("Error, no settings.xml found.")
|
||||
self.auth = False
|
||||
return False
|
||||
|
|
|
@ -13,17 +13,18 @@ from unicodedata import normalize
|
|||
import xml.etree.ElementTree as etree
|
||||
from functools import wraps
|
||||
from calendar import timegm
|
||||
from os.path import exists, join
|
||||
from os import remove, makedirs, walk
|
||||
from os.path import join
|
||||
from os import remove, walk, makedirs
|
||||
from shutil import rmtree
|
||||
from urllib import quote_plus
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
from xbmcvfs import exists, delete
|
||||
|
||||
from variables import DB_VIDEO_PATH, DB_MUSIC_PATH, DB_TEXTURE_PATH, \
|
||||
DB_PLEX_PATH, KODI_PROFILE
|
||||
DB_PLEX_PATH, KODI_PROFILE, KODIVERSION
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -91,6 +92,30 @@ def settings(setting, value=None):
|
|||
return tryDecode(addon.getSetting(setting))
|
||||
|
||||
|
||||
def exists_dir(path):
|
||||
"""
|
||||
Safe way to check whether the directory path exists already (broken in Kodi
|
||||
<17)
|
||||
|
||||
Feed with encoded string
|
||||
"""
|
||||
if KODIVERSION >= 17:
|
||||
answ = exists(path)
|
||||
else:
|
||||
dummyfile = join(path, 'dummyfile.txt')
|
||||
try:
|
||||
with open(dummyfile, 'w') as f:
|
||||
f.write('text')
|
||||
except IOError:
|
||||
# folder does not exist yet
|
||||
answ = 0
|
||||
else:
|
||||
# Folder exists. Delete file again.
|
||||
delete(dummyfile)
|
||||
answ = 1
|
||||
return answ
|
||||
|
||||
|
||||
def language(stringid):
|
||||
# Central string retrieval
|
||||
return ADDON.getLocalizedString(stringid)
|
||||
|
@ -322,7 +347,7 @@ def reset():
|
|||
for row in rows:
|
||||
tablename = row[0]
|
||||
if tablename != "version":
|
||||
cursor.execute("DELETE FROM " + tablename)
|
||||
cursor.execute("DELETE FROM ?", (tablename,))
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
|
||||
|
@ -335,7 +360,7 @@ def reset():
|
|||
for row in rows:
|
||||
tablename = row[0]
|
||||
if tablename != "version":
|
||||
cursor.execute("DELETE FROM " + tablename)
|
||||
cursor.execute("DELETE FROM ?", (tablename, ))
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
|
||||
|
@ -348,7 +373,7 @@ def reset():
|
|||
for row in rows:
|
||||
tablename = row[0]
|
||||
if tablename != "version":
|
||||
cursor.execute("DELETE FROM " + tablename)
|
||||
cursor.execute("DELETE FROM ?", (tablename, ))
|
||||
cursor.execute('DROP table IF EXISTS plex')
|
||||
cursor.execute('DROP table IF EXISTS view')
|
||||
connection.commit()
|
||||
|
@ -372,7 +397,7 @@ def reset():
|
|||
for row in rows:
|
||||
tableName = row[0]
|
||||
if(tableName != "version"):
|
||||
cursor.execute("DELETE FROM " + tableName)
|
||||
cursor.execute("DELETE FROM ?", (tableName, ))
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
|
||||
|
@ -542,8 +567,10 @@ def __setSubElement(element, subelement):
|
|||
def advancedsettings_xml(node_list, new_value=None, attrib=None,
|
||||
force_create=False):
|
||||
"""
|
||||
Returns the etree element for nodelist (if it exists) and the tree. None if
|
||||
not set
|
||||
Returns
|
||||
etree element, tree
|
||||
or
|
||||
None, None
|
||||
|
||||
node_list is a list of node names starting from the outside, ignoring the
|
||||
outter advancedsettings. Example nodelist=['video', 'busydialogdelayms']
|
||||
|
@ -576,7 +603,7 @@ def advancedsettings_xml(node_list, new_value=None, attrib=None,
|
|||
# Document is blank or missing
|
||||
if new_value is None and attrib is None and force_create is False:
|
||||
log.debug('Could not parse advancedsettings.xml, returning None')
|
||||
return
|
||||
return None, None
|
||||
# Create topmost xml entry
|
||||
tree = etree.ElementTree(element=etree.Element('advancedsettings'))
|
||||
root = tree.getroot()
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
import logging
|
||||
from shutil import copytree
|
||||
import xml.etree.ElementTree as etree
|
||||
from os import remove, listdir, makedirs
|
||||
from os.path import isfile, join
|
||||
|
||||
import xbmc
|
||||
from os import remove, makedirs, listdir
|
||||
from os.path import exists, isfile, join
|
||||
from xbmcvfs import exists
|
||||
|
||||
from utils import window, settings, language as lang, tryEncode, indent, \
|
||||
normalize_nodes
|
||||
normalize_nodes, exists_dir
|
||||
import variables as v
|
||||
|
||||
###############################################################################
|
||||
|
@ -74,14 +75,14 @@ class VideoNodes(object):
|
|||
return
|
||||
|
||||
# Verify the video directory
|
||||
if exists(path) is False:
|
||||
if not exists_dir(path):
|
||||
copytree(
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video"),
|
||||
dst=xbmc.translatePath("special://profile/library/video"))
|
||||
|
||||
# Create the node directory
|
||||
if mediatype != "photos":
|
||||
if exists(nodepath) is False:
|
||||
if not exists_dir(nodepath):
|
||||
# folder does not exist yet
|
||||
log.debug('Creating folder %s' % nodepath)
|
||||
makedirs(nodepath)
|
||||
|
@ -387,7 +388,7 @@ class VideoNodes(object):
|
|||
windowpath = "ActivateWindow(Video,%s,return)" % path
|
||||
|
||||
# Create the video node directory
|
||||
if not exists(nodepath):
|
||||
if not exists_dir(nodepath):
|
||||
# We need to copy over the default items
|
||||
copytree(
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video"),
|
||||
|
|
Loading…
Reference in a new issue