Merge branch 'hotfixes' of https://github.com/croneter/PlexKodiConnect into hotfixes
This commit is contained in:
commit
6c851bd3a6
12 changed files with 672 additions and 802 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-1.8.18-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
[![stable version](https://img.shields.io/badge/stable_version-1.8.18-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
||||||
[![beta version](https://img.shields.io/badge/beta_version-2.0.3-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
[![beta version](https://img.shields.io/badge/beta_version-2.0.4-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
||||||
|
|
||||||
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
[![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)
|
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||||
|
|
19
addon.xml
19
addon.xml
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.0.3" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.0.4" provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
<import addon="script.module.requests" version="2.9.1" />
|
<import addon="script.module.requests" version="2.9.1" />
|
||||||
|
@ -61,7 +61,22 @@
|
||||||
<summary lang="da_DK">Indbygget Integration af Plex i Kodi</summary>
|
<summary lang="da_DK">Indbygget Integration af Plex i Kodi</summary>
|
||||||
<description lang="da_DK">Tilslut Kodi til din Plex Media Server. Dette plugin forudsætter, at du administrere alle dine videoer med Plex (og ikke med Kodi). Du kan miste data som allerede er gemt i Kodi video og musik-databaser (dette plugin ændrer direkte i dem). Brug på eget ansvar!</description>
|
<description lang="da_DK">Tilslut Kodi til din Plex Media Server. Dette plugin forudsætter, at du administrere alle dine videoer med Plex (og ikke med Kodi). Du kan miste data som allerede er gemt i Kodi video og musik-databaser (dette plugin ændrer direkte i dem). Brug på eget ansvar!</description>
|
||||||
<disclaimer lang="da_DK">Brug på eget ansvar</disclaimer>
|
<disclaimer lang="da_DK">Brug på eget ansvar</disclaimer>
|
||||||
<news>version 2.0.3 (beta only):
|
<news>version 2.0.4 (beta only):
|
||||||
|
- WARNING: You will need to reset the Kodi database!
|
||||||
|
- Many improvements to the Kodi database handling which should get rid of some weird bugs
|
||||||
|
- Many improvements to playback startup
|
||||||
|
- Fix info screen and actors not working
|
||||||
|
- Fix Companion displaying and selecting wrong subtitle
|
||||||
|
- Don't cache subtitles if direct playing
|
||||||
|
- Wipe all existing resume point, e.g. on user switch
|
||||||
|
- Don't mess with Kodi's screensaver settings
|
||||||
|
- Inhibit idle shutdown only during initial sync
|
||||||
|
- Fix KeyError for server discovery
|
||||||
|
- Increase Python requests dependency to version 2.9.1
|
||||||
|
- Re-introduce PlexKodiConnect dependency add-ons for movies and tv shows
|
||||||
|
- And a lot of other stuff
|
||||||
|
|
||||||
|
version 2.0.3 (beta only):
|
||||||
- Fix Alexa playback
|
- Fix Alexa playback
|
||||||
- Fix Kodi boot loop
|
- Fix Kodi boot loop
|
||||||
- Fix playback being reported to the wrong Plex user
|
- Fix playback being reported to the wrong Plex user
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
version 2.0.4 (beta only):
|
||||||
|
- WARNING: You will need to reset the Kodi database!
|
||||||
|
- Many improvements to the Kodi database handling which should get rid of some weird bugs
|
||||||
|
- Many improvements to playback startup
|
||||||
|
- Fix info screen and actors not working
|
||||||
|
- Fix Companion displaying and selecting wrong subtitle
|
||||||
|
- Don't cache subtitles if direct playing
|
||||||
|
- Wipe all existing resume point, e.g. on user switch
|
||||||
|
- Don't mess with Kodi's screensaver settings
|
||||||
|
- Inhibit idle shutdown only during initial sync
|
||||||
|
- Fix KeyError for server discovery
|
||||||
|
- Increase Python requests dependency to version 2.9.1
|
||||||
|
- Re-introduce PlexKodiConnect dependency add-ons for movies and tv shows
|
||||||
|
- And a lot of other stuff
|
||||||
|
|
||||||
version 2.0.3 (beta only):
|
version 2.0.3 (beta only):
|
||||||
- Fix Alexa playback
|
- Fix Alexa playback
|
||||||
- Fix Kodi boot loop
|
- Fix Kodi boot loop
|
||||||
|
|
|
@ -1670,10 +1670,6 @@ msgctxt "#39213"
|
||||||
msgid "is offline"
|
msgid "is offline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "#39214"
|
|
||||||
msgid "Even though we signed in to plex.tv, we could not authorize for PMS"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgctxt "#39215"
|
msgctxt "#39215"
|
||||||
msgid "Enter your Plex Media Server's IP or URL, Examples are:"
|
msgid "Enter your Plex Media Server's IP or URL, Examples are:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -41,7 +41,7 @@ from xbmcvfs import exists
|
||||||
import clientinfo as client
|
import clientinfo as client
|
||||||
from downloadutils import DownloadUtils as DU
|
from downloadutils import DownloadUtils as DU
|
||||||
from utils import window, settings, language as lang, try_decode, try_encode, \
|
from utils import window, settings, language as lang, try_decode, try_encode, \
|
||||||
unix_date_to_kodi, exists_dir, slugify, dialog
|
unix_date_to_kodi, exists_dir, slugify, dialog, escape_html
|
||||||
import PlexFunctions as PF
|
import PlexFunctions as PF
|
||||||
import plexdb_functions as plexdb
|
import plexdb_functions as plexdb
|
||||||
import variables as v
|
import variables as v
|
||||||
|
@ -337,22 +337,14 @@ class API(object):
|
||||||
"""
|
"""
|
||||||
people = []
|
people = []
|
||||||
for child in self.item:
|
for child in self.item:
|
||||||
if child.tag in PEOPLE_OF_INTEREST.keys():
|
if child.tag in PEOPLE_OF_INTEREST:
|
||||||
name = child.attrib['tag']
|
|
||||||
name_id = child.attrib['id']
|
|
||||||
typus = PEOPLE_OF_INTEREST[child.tag]
|
|
||||||
url = child.get('thumb')
|
|
||||||
role = child.get('role')
|
|
||||||
people.append({
|
people.append({
|
||||||
'Name': name,
|
'Name': child.attrib['tag'],
|
||||||
'Type': typus,
|
'Type': PEOPLE_OF_INTEREST[child.tag],
|
||||||
'Id': name_id,
|
'Id': child.attrib['id'],
|
||||||
'imageurl': url
|
'imageurl': child.get('thumb'),
|
||||||
|
'Role': child.get('role')
|
||||||
})
|
})
|
||||||
if url:
|
|
||||||
people[-1].update({'imageurl': url})
|
|
||||||
if role:
|
|
||||||
people[-1].update({'Role': role})
|
|
||||||
return people
|
return people
|
||||||
|
|
||||||
def genre_list(self):
|
def genre_list(self):
|
||||||
|
@ -365,6 +357,17 @@ class API(object):
|
||||||
genre.append(child.attrib['tag'])
|
genre.append(child.attrib['tag'])
|
||||||
return genre
|
return genre
|
||||||
|
|
||||||
|
def guid_html_escaped(self):
|
||||||
|
"""
|
||||||
|
Returns the 'guid' attribute, e.g.
|
||||||
|
'com.plexapp.agents.thetvdb://76648/2/4?lang=en'
|
||||||
|
as an HTML-escaped string or None
|
||||||
|
"""
|
||||||
|
answ = self.item.get('guid')
|
||||||
|
if answ is not None:
|
||||||
|
answ = escape_html(answ)
|
||||||
|
return answ
|
||||||
|
|
||||||
def provider(self, providername=None):
|
def provider(self, providername=None):
|
||||||
"""
|
"""
|
||||||
providername: e.g. 'imdb', 'tvdb'
|
providername: e.g. 'imdb', 'tvdb'
|
||||||
|
@ -642,7 +645,8 @@ class API(object):
|
||||||
"""
|
"""
|
||||||
Returns the ratingKey (plex_id) of the trailer or None
|
Returns the ratingKey (plex_id) of the trailer or None
|
||||||
"""
|
"""
|
||||||
for extra in self.item.iterfind('Extras'):
|
for extras in self.item.iterfind('Extras'):
|
||||||
|
for extra in extras:
|
||||||
try:
|
try:
|
||||||
typus = int(extra.attrib['extraType'])
|
typus = int(extra.attrib['extraType'])
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
|
|
|
@ -310,15 +310,9 @@ class Artwork():
|
||||||
self.cacheTexture(imageUrl)
|
self.cacheTexture(imageUrl)
|
||||||
|
|
||||||
def deleteArtwork(self, kodiId, mediaType, cursor):
|
def deleteArtwork(self, kodiId, mediaType, cursor):
|
||||||
query = ' '.join((
|
query = 'SELECT url FROM art WHERE media_id = ? AND media_type = ?'
|
||||||
"SELECT url",
|
|
||||||
"FROM art",
|
|
||||||
"WHERE media_id = ?",
|
|
||||||
"AND media_type = ?"
|
|
||||||
))
|
|
||||||
cursor.execute(query, (kodiId, mediaType,))
|
cursor.execute(query, (kodiId, mediaType,))
|
||||||
rows = cursor.fetchall()
|
for row in cursor.fetchall():
|
||||||
for row in rows:
|
|
||||||
self.deleteCachedArtwork(row[0])
|
self.deleteCachedArtwork(row[0])
|
||||||
|
|
||||||
def deleteCachedArtwork(self, url):
|
def deleteCachedArtwork(self, url):
|
||||||
|
@ -330,7 +324,7 @@ class Artwork():
|
||||||
(url,))
|
(url,))
|
||||||
cachedurl = cursor.fetchone()[0]
|
cachedurl = cursor.fetchone()[0]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
LOG.info("Could not find cached url.")
|
LOG.debug("Could not find cached url.")
|
||||||
else:
|
else:
|
||||||
# Delete thumbnail as well as the entry
|
# Delete thumbnail as well as the entry
|
||||||
path = translatePath("special://thumbnails/%s" % cachedurl)
|
path = translatePath("special://thumbnails/%s" % cachedurl)
|
||||||
|
|
|
@ -317,7 +317,6 @@ class InitialSetup(object):
|
||||||
Returns server or None if unsuccessful
|
Returns server or None if unsuccessful
|
||||||
"""
|
"""
|
||||||
https_updated = False
|
https_updated = False
|
||||||
checked_plex_tv = False
|
|
||||||
server = None
|
server = None
|
||||||
while True:
|
while True:
|
||||||
if https_updated is False:
|
if https_updated is False:
|
||||||
|
@ -340,25 +339,6 @@ class InitialSetup(object):
|
||||||
server['scheme'] = 'https'
|
server['scheme'] = 'https'
|
||||||
https_updated = True
|
https_updated = True
|
||||||
continue
|
continue
|
||||||
if chk == 401:
|
|
||||||
LOG.warn('Not yet authorized for Plex server %s',
|
|
||||||
server['name'])
|
|
||||||
if self.check_plex_tv_sign_in() is True:
|
|
||||||
if checked_plex_tv is False:
|
|
||||||
# Try again
|
|
||||||
checked_plex_tv = True
|
|
||||||
https_updated = False
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
LOG.warn('Not authorized even though we are signed '
|
|
||||||
' in to plex.tv correctly')
|
|
||||||
dialog('ok',
|
|
||||||
lang(29999),
|
|
||||||
'%s %s' % (lang(39214),
|
|
||||||
try_encode(server['name'])))
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
# Problems connecting
|
# Problems connecting
|
||||||
elif chk >= 400 or chk is False:
|
elif chk >= 400 or chk is False:
|
||||||
LOG.warn('Problems connecting to server %s. chk is %s',
|
LOG.warn('Problems connecting to server %s. chk is %s',
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Items(object):
|
||||||
self.kodiconn = kodi_sql('video')
|
self.kodiconn = kodi_sql('video')
|
||||||
self.kodicursor = self.kodiconn.cursor()
|
self.kodicursor = self.kodiconn.cursor()
|
||||||
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
|
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
|
||||||
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
|
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
@ -326,6 +326,7 @@ class Movies(Items):
|
||||||
"imdb",
|
"imdb",
|
||||||
uniqueid)
|
uniqueid)
|
||||||
else:
|
else:
|
||||||
|
self.kodi_db.remove_uniqueid(movieid, v.KODI_TYPE_MOVIE)
|
||||||
uniqueid = -1
|
uniqueid = -1
|
||||||
query = '''
|
query = '''
|
||||||
UPDATE movie
|
UPDATE movie
|
||||||
|
@ -360,7 +361,8 @@ class Movies(Items):
|
||||||
LOG.info("ADD movie itemid: %s - Title: %s", itemid, title)
|
LOG.info("ADD movie itemid: %s - Title: %s", itemid, title)
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
# add new ratings Kodi 17
|
# add new ratings Kodi 17
|
||||||
rating_id = self.kodi_db.create_entry_rating()
|
rating_id = self.kodi_db.get_ratingid(movieid,
|
||||||
|
v.KODI_TYPE_MOVIE)
|
||||||
self.kodi_db.add_ratings(rating_id,
|
self.kodi_db.add_ratings(rating_id,
|
||||||
movieid,
|
movieid,
|
||||||
v.KODI_TYPE_MOVIE,
|
v.KODI_TYPE_MOVIE,
|
||||||
|
@ -369,7 +371,8 @@ class Movies(Items):
|
||||||
votecount)
|
votecount)
|
||||||
# add new uniqueid Kodi 17
|
# add new uniqueid Kodi 17
|
||||||
if imdb is not None:
|
if imdb is not None:
|
||||||
uniqueid = self.kodi_db.create_entry_uniqueid()
|
uniqueid = self.kodi_db.get_uniqueid(movieid,
|
||||||
|
v.KODI_TYPE_MOVIE)
|
||||||
self.kodi_db.add_uniqueid(uniqueid,
|
self.kodi_db.add_uniqueid(uniqueid,
|
||||||
movieid,
|
movieid,
|
||||||
v.KODI_TYPE_MOVIE,
|
v.KODI_TYPE_MOVIE,
|
||||||
|
@ -434,23 +437,23 @@ class Movies(Items):
|
||||||
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
|
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
|
||||||
|
|
||||||
# Process countries
|
# Process countries
|
||||||
self.kodi_db.addCountries(movieid, countries, "movie")
|
self.kodi_db.modify_countries(movieid, v.KODI_TYPE_MOVIE, countries)
|
||||||
# Process cast
|
# Process cast
|
||||||
self.kodi_db.addPeople(movieid, api.people_list(), "movie")
|
self.kodi_db.addPeople(movieid, api.people_list(), "movie")
|
||||||
# Process genres
|
# Process genres
|
||||||
self.kodi_db.addGenres(movieid, genres, "movie")
|
self.kodi_db.modify_genres(movieid, v.KODI_TYPE_MOVIE, genres)
|
||||||
# Process artwork
|
# Process artwork
|
||||||
artwork.addArtwork(api.artwork(), movieid, "movie", kodicursor)
|
artwork.addArtwork(api.artwork(), movieid, "movie", kodicursor)
|
||||||
# Process stream details
|
# Process stream details
|
||||||
self.kodi_db.addStreams(fileid, api.mediastreams(), runtime)
|
self.kodi_db.modify_streams(fileid, api.mediastreams(), runtime)
|
||||||
# Process studios
|
# Process studios
|
||||||
self.kodi_db.addStudios(movieid, studios, "movie")
|
self.kodi_db.modify_studios(movieid, v.KODI_TYPE_MOVIE, studios)
|
||||||
# Process tags: view, Plex collection tags
|
# Process tags: view, Plex collection tags
|
||||||
tags = [viewtag]
|
tags = [viewtag]
|
||||||
tags.extend(collections)
|
tags.extend(collections)
|
||||||
if userdata['Favorite']:
|
if userdata['Favorite']:
|
||||||
tags.append("Favorite movies")
|
tags.append("Favorite movies")
|
||||||
self.kodi_db.addTags(movieid, tags, "movie")
|
self.kodi_db.modify_tags(movieid, v.KODI_TYPE_MOVIE, tags)
|
||||||
# Add any sets from Plex collection tags
|
# Add any sets from Plex collection tags
|
||||||
self.kodi_db.addSets(movieid, collections, kodicursor)
|
self.kodi_db.addSets(movieid, collections, kodicursor)
|
||||||
# Process playstates
|
# Process playstates
|
||||||
|
@ -469,7 +472,7 @@ class Movies(Items):
|
||||||
kodi_id = plex_dbitem[0]
|
kodi_id = plex_dbitem[0]
|
||||||
file_id = plex_dbitem[1]
|
file_id = plex_dbitem[1]
|
||||||
kodi_type = plex_dbitem[4]
|
kodi_type = plex_dbitem[4]
|
||||||
LOG.info("Removing %sid: %s file_id: %s",
|
LOG.debug("Removing %sid: %s file_id: %s",
|
||||||
kodi_type, kodi_id, file_id)
|
kodi_type, kodi_id, file_id)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return
|
return
|
||||||
|
@ -480,11 +483,21 @@ class Movies(Items):
|
||||||
artwork.deleteArtwork(kodi_id, kodi_type, kodicursor)
|
artwork.deleteArtwork(kodi_id, kodi_type, kodicursor)
|
||||||
|
|
||||||
if kodi_type == v.KODI_TYPE_MOVIE:
|
if kodi_type == v.KODI_TYPE_MOVIE:
|
||||||
|
set_id = self.kodi_db.get_set_id(kodi_id)
|
||||||
|
self.kodi_db.delete_countries(kodi_id, kodi_type)
|
||||||
|
self.kodi_db.delete_people(kodi_id, kodi_type)
|
||||||
|
self.kodi_db.delete_genre(kodi_id, kodi_type)
|
||||||
|
self.kodi_db.delete_studios(kodi_id, kodi_type)
|
||||||
|
self.kodi_db.delete_tags(kodi_id, kodi_type)
|
||||||
|
self.kodi_db.modify_streams(file_id)
|
||||||
|
self.kodi_db.delete_playstate(file_id)
|
||||||
# Delete kodi movie and file
|
# Delete kodi movie and file
|
||||||
kodicursor.execute("DELETE FROM movie WHERE idMovie = ?",
|
kodicursor.execute("DELETE FROM movie WHERE idMovie = ?",
|
||||||
(kodi_id,))
|
(kodi_id,))
|
||||||
kodicursor.execute("DELETE FROM files WHERE idFile = ?",
|
kodicursor.execute("DELETE FROM files WHERE idFile = ?",
|
||||||
(file_id,))
|
(file_id,))
|
||||||
|
if set_id:
|
||||||
|
self.kodi_db.delete_possibly_empty_set(set_id)
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
self.kodi_db.remove_uniqueid(kodi_id, kodi_type)
|
self.kodi_db.remove_uniqueid(kodi_id, kodi_type)
|
||||||
self.kodi_db.remove_ratings(kodi_id, kodi_type)
|
self.kodi_db.remove_ratings(kodi_id, kodi_type)
|
||||||
|
@ -499,7 +512,7 @@ class Movies(Items):
|
||||||
# Update plex reference
|
# Update plex reference
|
||||||
plex_db.updateParentId(plexid, None)
|
plex_db.updateParentId(plexid, None)
|
||||||
kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodi_id,))
|
kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodi_id,))
|
||||||
LOG.info("Deleted %s %s from kodi database", kodi_type, itemid)
|
LOG.debug("Deleted %s %s from kodi database", kodi_type, itemid)
|
||||||
|
|
||||||
|
|
||||||
class TVShows(Items):
|
class TVShows(Items):
|
||||||
|
@ -627,6 +640,7 @@ class TVShows(Items):
|
||||||
"unknown",
|
"unknown",
|
||||||
uniqueid)
|
uniqueid)
|
||||||
else:
|
else:
|
||||||
|
self.kodi_db.remove_uniqueid(showid, v.KODI_TYPE_SHOW)
|
||||||
uniqueid = -1
|
uniqueid = -1
|
||||||
# Update the tvshow entry
|
# Update the tvshow entry
|
||||||
query = '''
|
query = '''
|
||||||
|
@ -677,7 +691,7 @@ class TVShows(Items):
|
||||||
view_id=viewid)
|
view_id=viewid)
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
# add new ratings Kodi 17
|
# add new ratings Kodi 17
|
||||||
rating_id = self.kodi_db.create_entry_rating()
|
rating_id = self.kodi_db.get_ratingid(showid, v.KODI_TYPE_SHOW)
|
||||||
self.kodi_db.add_ratings(rating_id,
|
self.kodi_db.add_ratings(rating_id,
|
||||||
showid,
|
showid,
|
||||||
v.KODI_TYPE_SHOW,
|
v.KODI_TYPE_SHOW,
|
||||||
|
@ -686,7 +700,8 @@ class TVShows(Items):
|
||||||
votecount)
|
votecount)
|
||||||
# add new uniqueid Kodi 17
|
# add new uniqueid Kodi 17
|
||||||
if tvdb is not None:
|
if tvdb is not None:
|
||||||
uniqueid = self.kodi_db.create_entry_uniqueid()
|
uniqueid = self.kodi_db.get_uniqueid(showid,
|
||||||
|
v.KODI_TYPE_SHOW)
|
||||||
self.kodi_db.add_uniqueid(uniqueid,
|
self.kodi_db.add_uniqueid(uniqueid,
|
||||||
showid,
|
showid,
|
||||||
v.KODI_TYPE_SHOW,
|
v.KODI_TYPE_SHOW,
|
||||||
|
@ -985,7 +1000,8 @@ class TVShows(Items):
|
||||||
# Create the episode entry
|
# Create the episode entry
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
# add new ratings Kodi 17
|
# add new ratings Kodi 17
|
||||||
rating_id = self.kodi_db.create_entry_rating()
|
rating_id = self.kodi_db.get_ratingid(episodeid,
|
||||||
|
v.KODI_TYPE_EPISODE)
|
||||||
self.kodi_db.add_ratings(rating_id,
|
self.kodi_db.add_ratings(rating_id,
|
||||||
episodeid,
|
episodeid,
|
||||||
v.KODI_TYPE_EPISODE,
|
v.KODI_TYPE_EPISODE,
|
||||||
|
@ -993,7 +1009,9 @@ class TVShows(Items):
|
||||||
rating,
|
rating,
|
||||||
votecount)
|
votecount)
|
||||||
# add new uniqueid Kodi 17
|
# add new uniqueid Kodi 17
|
||||||
self.kodi_db.add_uniqueid(self.kodi_db.create_entry_uniqueid(),
|
uniqueid = self.kodi_db.get_uniqueid(episodeid,
|
||||||
|
v.KODI_TYPE_EPISODE)
|
||||||
|
self.kodi_db.add_uniqueid(uniqueid,
|
||||||
episodeid,
|
episodeid,
|
||||||
v.KODI_TYPE_EPISODE,
|
v.KODI_TYPE_EPISODE,
|
||||||
tvdb,
|
tvdb,
|
||||||
|
@ -1083,7 +1101,7 @@ class TVShows(Items):
|
||||||
|
|
||||||
# Process stream details
|
# Process stream details
|
||||||
streams = api.mediastreams()
|
streams = api.mediastreams()
|
||||||
self.kodi_db.addStreams(fileid, streams, runtime)
|
self.kodi_db.modify_streams(fileid, streams, runtime)
|
||||||
# Process playstates
|
# Process playstates
|
||||||
self.kodi_db.addPlaystate(fileid,
|
self.kodi_db.addPlaystate(fileid,
|
||||||
resume,
|
resume,
|
||||||
|
@ -1203,6 +1221,9 @@ class TVShows(Items):
|
||||||
Remove a TV show, and only the show, no seasons or episodes
|
Remove a TV show, and only the show, no seasons or episodes
|
||||||
"""
|
"""
|
||||||
kodicursor = self.kodicursor
|
kodicursor = self.kodicursor
|
||||||
|
self.kodi_db.delete_genre(kodi_id, v.KODI_TYPE_SHOW)
|
||||||
|
self.kodi_db.delete_studios(kodi_id, v.KODI_TYPE_SHOW)
|
||||||
|
self.kodi_db.delete_tags(kodi_id, v.KODI_TYPE_SHOW)
|
||||||
self.artwork.deleteArtwork(kodi_id, v.KODI_TYPE_SHOW, kodicursor)
|
self.artwork.deleteArtwork(kodi_id, v.KODI_TYPE_SHOW, kodicursor)
|
||||||
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,))
|
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,))
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
|
@ -1220,15 +1241,18 @@ class TVShows(Items):
|
||||||
(kodi_id,))
|
(kodi_id,))
|
||||||
LOG.info("Removed season: %s.", kodi_id)
|
LOG.info("Removed season: %s.", kodi_id)
|
||||||
|
|
||||||
def removeEpisode(self, kodi_id, fileid):
|
def removeEpisode(self, kodi_id, file_id):
|
||||||
"""
|
"""
|
||||||
Remove an episode, and episode only
|
Remove an episode, and episode only
|
||||||
"""
|
"""
|
||||||
kodicursor = self.kodicursor
|
kodicursor = self.kodicursor
|
||||||
|
self.kodi_db.delete_people(kodi_id, v.KODI_TYPE_EPISODE)
|
||||||
|
self.kodi_db.modify_streams(file_id)
|
||||||
|
self.kodi_db.delete_playstate(file_id)
|
||||||
self.artwork.deleteArtwork(kodi_id, "episode", kodicursor)
|
self.artwork.deleteArtwork(kodi_id, "episode", kodicursor)
|
||||||
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?",
|
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?",
|
||||||
(kodi_id,))
|
(kodi_id,))
|
||||||
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
|
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (file_id,))
|
||||||
if v.KODIVERSION >= 17:
|
if v.KODIVERSION >= 17:
|
||||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE)
|
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE)
|
||||||
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_EPISODE)
|
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_EPISODE)
|
||||||
|
@ -1250,7 +1274,7 @@ class Music(Items):
|
||||||
self.kodiconn = kodi_sql('music')
|
self.kodiconn = kodi_sql('music')
|
||||||
self.kodicursor = self.kodiconn.cursor()
|
self.kodicursor = self.kodiconn.cursor()
|
||||||
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
|
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
|
||||||
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
|
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@catch_exceptions(warnuser=True)
|
@catch_exceptions(warnuser=True)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,9 +24,9 @@ import variables as v
|
||||||
import state
|
import state
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
LOG = getLogger("PLEX." + __name__)
|
LOG = getLogger("PLEX." + __name__)
|
||||||
|
# Do we need to return ultimately with a setResolvedUrl?
|
||||||
|
RESOLVE = True
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,13 +49,13 @@ def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
|
||||||
"""
|
"""
|
||||||
LOG.info('playback_triage called with plex_id %s, plex_type %s, path %s',
|
LOG.info('playback_triage called with plex_id %s, plex_type %s, path %s',
|
||||||
plex_id, plex_type, path)
|
plex_id, plex_type, path)
|
||||||
|
global RESOLVE
|
||||||
|
RESOLVE = resolve
|
||||||
if not state.AUTHENTICATED:
|
if not state.AUTHENTICATED:
|
||||||
LOG.error('Not yet authenticated for PMS, abort starting playback')
|
LOG.error('Not yet authenticated for PMS, abort starting playback')
|
||||||
if resolve is True:
|
|
||||||
# Release default.py
|
|
||||||
pickle_me(Playback_Successful())
|
|
||||||
# "Unauthorized for PMS"
|
# "Unauthorized for PMS"
|
||||||
dialog('notification', lang(29999), lang(30017))
|
dialog('notification', lang(29999), lang(30017))
|
||||||
|
_ensure_resolve()
|
||||||
return
|
return
|
||||||
playqueue = PQ.get_playqueue_from_type(
|
playqueue = PQ.get_playqueue_from_type(
|
||||||
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
|
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
|
||||||
|
@ -67,19 +67,13 @@ def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
|
||||||
try:
|
try:
|
||||||
playqueue.items[pos]
|
playqueue.items[pos]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Release our default.py before starting our own Kodi player instance
|
_playback_init(plex_id, plex_type, playqueue, pos)
|
||||||
if resolve is True:
|
|
||||||
state.PKC_CAUSED_STOP = True
|
|
||||||
result = Playback_Successful()
|
|
||||||
result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
|
|
||||||
pickle_me(result)
|
|
||||||
playback_init(plex_id, plex_type, playqueue)
|
|
||||||
else:
|
else:
|
||||||
# kick off playback on second pass
|
# kick off playback on second pass
|
||||||
conclude_playback(playqueue, pos)
|
_conclude_playback(playqueue, pos)
|
||||||
|
|
||||||
|
|
||||||
def playback_init(plex_id, plex_type, playqueue):
|
def _playback_init(plex_id, plex_type, playqueue, pos):
|
||||||
"""
|
"""
|
||||||
Playback setup if Kodi starts playing an item for the first time.
|
Playback setup if Kodi starts playing an item for the first time.
|
||||||
"""
|
"""
|
||||||
|
@ -91,9 +85,25 @@ def playback_init(plex_id, plex_type, playqueue):
|
||||||
LOG.error('Could not get a PMS xml for plex id %s', plex_id)
|
LOG.error('Could not get a PMS xml for plex id %s', plex_id)
|
||||||
# "Play error"
|
# "Play error"
|
||||||
dialog('notification', lang(29999), lang(30128), icon='{error}')
|
dialog('notification', lang(29999), lang(30128), icon='{error}')
|
||||||
|
_ensure_resolve()
|
||||||
return
|
return
|
||||||
trailers = False
|
if playqueue.kodi_pl.size() > 1:
|
||||||
|
# Special case - we already got a filled Kodi playqueue
|
||||||
|
try:
|
||||||
|
_init_existing_kodi_playlist(playqueue)
|
||||||
|
except PL.PlaylistError:
|
||||||
|
LOG.error('Aborting playback_init for longer Kodi playlist')
|
||||||
|
_ensure_resolve()
|
||||||
|
return
|
||||||
|
# Now we need to use setResolvedUrl for the item at position pos
|
||||||
|
_conclude_playback(playqueue, pos)
|
||||||
|
return
|
||||||
|
# "Usual" case - consider trailers and parts and build both Kodi and Plex
|
||||||
|
# playqueues
|
||||||
|
# Fail the item we're trying to play now so we can restart the player
|
||||||
|
_ensure_resolve()
|
||||||
api = API(xml[0])
|
api = API(xml[0])
|
||||||
|
trailers = False
|
||||||
if (plex_type == v.PLEX_TYPE_MOVIE and not api.resume_point() and
|
if (plex_type == v.PLEX_TYPE_MOVIE and not api.resume_point() and
|
||||||
settings('enableCinema') == "true"):
|
settings('enableCinema') == "true"):
|
||||||
if settings('askCinema') == "true":
|
if settings('askCinema') == "true":
|
||||||
|
@ -115,6 +125,7 @@ def playback_init(plex_id, plex_type, playqueue):
|
||||||
plex_id, xml.attrib.get('librarySectionUUID'))
|
plex_id, xml.attrib.get('librarySectionUUID'))
|
||||||
# "Play error"
|
# "Play error"
|
||||||
dialog('notification', lang(29999), lang(30128), icon='{error}')
|
dialog('notification', lang(29999), lang(30128), icon='{error}')
|
||||||
|
_ensure_resolve()
|
||||||
return
|
return
|
||||||
# Should already be empty, but just in case
|
# Should already be empty, but just in case
|
||||||
PL.get_playlist_details_from_xml(playqueue, xml)
|
PL.get_playlist_details_from_xml(playqueue, xml)
|
||||||
|
@ -139,6 +150,39 @@ def playback_init(plex_id, plex_type, playqueue):
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_resolve():
|
||||||
|
"""
|
||||||
|
Will check whether RESOLVE=True and if so, fail Kodi playback startup
|
||||||
|
with the path 'PKC_Dummy_Path_Which_Fails' using setResolvedUrl (and some
|
||||||
|
pickling)
|
||||||
|
|
||||||
|
This way we're making sure that other Python instances (calling default.py)
|
||||||
|
will be destroyed.
|
||||||
|
"""
|
||||||
|
if RESOLVE is True:
|
||||||
|
state.PKC_CAUSED_STOP = True
|
||||||
|
result = Playback_Successful()
|
||||||
|
result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
|
||||||
|
pickle_me(result)
|
||||||
|
|
||||||
|
|
||||||
|
def _init_existing_kodi_playlist(playqueue):
|
||||||
|
"""
|
||||||
|
Will take the playqueue's kodi_pl with MORE than 1 element and initiate
|
||||||
|
playback (without adding trailers)
|
||||||
|
"""
|
||||||
|
LOG.debug('Kodi playlist size: %s', playqueue.kodi_pl.size())
|
||||||
|
for i, kodi_item in enumerate(js.playlist_get_items(playqueue.playlistid)):
|
||||||
|
if i == 0:
|
||||||
|
item = PL.init_Plex_playlist(playqueue, kodi_item=kodi_item)
|
||||||
|
else:
|
||||||
|
item = PL.add_item_to_PMS_playlist(playqueue,
|
||||||
|
i,
|
||||||
|
kodi_item=kodi_item)
|
||||||
|
item.force_transcode = state.FORCE_TRANSCODE
|
||||||
|
LOG.debug('Done building Plex playlist from Kodi playlist')
|
||||||
|
|
||||||
|
|
||||||
def _prep_playlist_stack(xml):
|
def _prep_playlist_stack(xml):
|
||||||
stack = []
|
stack = []
|
||||||
for item in xml:
|
for item in xml:
|
||||||
|
@ -152,7 +196,9 @@ def _prep_playlist_stack(xml):
|
||||||
kodi_id = plex_dbitem[0] if plex_dbitem else None
|
kodi_id = plex_dbitem[0] if plex_dbitem else None
|
||||||
kodi_type = plex_dbitem[4] if plex_dbitem else None
|
kodi_type = plex_dbitem[4] if plex_dbitem else None
|
||||||
else:
|
else:
|
||||||
# We will never store clips (trailers) in the Kodi DB
|
# We will never store clips (trailers) in the Kodi DB.
|
||||||
|
# Also set kodi_id to None for playback via PMS, so that we're
|
||||||
|
# using add-on paths.
|
||||||
kodi_id = None
|
kodi_id = None
|
||||||
kodi_type = None
|
kodi_type = None
|
||||||
for part, _ in enumerate(item[0]):
|
for part, _ in enumerate(item[0]):
|
||||||
|
@ -165,8 +211,7 @@ def _prep_playlist_stack(xml):
|
||||||
'plex_type': api.plex_type()
|
'plex_type': api.plex_type()
|
||||||
}
|
}
|
||||||
path = ('plugin://%s/?%s'
|
path = ('plugin://%s/?%s'
|
||||||
% (v.ADDON_TYPE[api.plex_type()],
|
% (v.ADDON_TYPE[api.plex_type()], urlencode(params)))
|
||||||
urlencode(params)))
|
|
||||||
listitem = api.create_listitem()
|
listitem = api.create_listitem()
|
||||||
listitem.setPath(try_encode(path))
|
listitem.setPath(try_encode(path))
|
||||||
else:
|
else:
|
||||||
|
@ -217,7 +262,7 @@ def _process_stack(playqueue, stack):
|
||||||
pos += 1
|
pos += 1
|
||||||
|
|
||||||
|
|
||||||
def conclude_playback(playqueue, pos):
|
def _conclude_playback(playqueue, pos):
|
||||||
"""
|
"""
|
||||||
ONLY if actually being played (e.g. at 5th position of a playqueue).
|
ONLY if actually being played (e.g. at 5th position of a playqueue).
|
||||||
|
|
||||||
|
@ -246,9 +291,9 @@ def conclude_playback(playqueue, pos):
|
||||||
else:
|
else:
|
||||||
playurl = item.file
|
playurl = item.file
|
||||||
listitem.setPath(try_encode(playurl))
|
listitem.setPath(try_encode(playurl))
|
||||||
if item.playmethod in ('DirectStream', 'DirectPlay'):
|
if item.playmethod == 'DirectStream':
|
||||||
listitem.setSubtitles(api.cache_external_subs())
|
listitem.setSubtitles(api.cache_external_subs())
|
||||||
else:
|
elif item.playmethod == 'Transcode':
|
||||||
playutils.audio_subtitle_prefs(listitem)
|
playutils.audio_subtitle_prefs(listitem)
|
||||||
if state.RESUME_PLAYBACK is True:
|
if state.RESUME_PLAYBACK is True:
|
||||||
state.RESUME_PLAYBACK = False
|
state.RESUME_PLAYBACK = False
|
||||||
|
@ -281,6 +326,8 @@ def process_indirect(key, offset, resolve=True):
|
||||||
setResolvedUrl
|
setResolvedUrl
|
||||||
"""
|
"""
|
||||||
LOG.info('process_indirect called with key: %s, offset: %s', key, offset)
|
LOG.info('process_indirect called with key: %s, offset: %s', key, offset)
|
||||||
|
global RESOLVE
|
||||||
|
RESOLVE = resolve
|
||||||
result = Playback_Successful()
|
result = Playback_Successful()
|
||||||
if key.startswith('http') or key.startswith('{server}'):
|
if key.startswith('http') or key.startswith('{server}'):
|
||||||
xml = DU().downloadUrl(key)
|
xml = DU().downloadUrl(key)
|
||||||
|
@ -292,9 +339,7 @@ def process_indirect(key, offset, resolve=True):
|
||||||
xml[0].attrib
|
xml[0].attrib
|
||||||
except (TypeError, IndexError, AttributeError):
|
except (TypeError, IndexError, AttributeError):
|
||||||
LOG.error('Could not download PMS metadata')
|
LOG.error('Could not download PMS metadata')
|
||||||
if resolve is True:
|
_ensure_resolve()
|
||||||
# Release default.py
|
|
||||||
pickle_me(result)
|
|
||||||
return
|
return
|
||||||
if offset != '0':
|
if offset != '0':
|
||||||
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
|
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
|
||||||
|
@ -317,9 +362,7 @@ def process_indirect(key, offset, resolve=True):
|
||||||
xml[0].attrib
|
xml[0].attrib
|
||||||
except (TypeError, IndexError, AttributeError):
|
except (TypeError, IndexError, AttributeError):
|
||||||
LOG.error('Could not download last xml for playurl')
|
LOG.error('Could not download last xml for playurl')
|
||||||
if resolve is True:
|
_ensure_resolve()
|
||||||
# Release default.py
|
|
||||||
pickle_me(result)
|
|
||||||
return
|
return
|
||||||
playurl = xml[0].attrib['key']
|
playurl = xml[0].attrib['key']
|
||||||
item.file = playurl
|
item.file = playurl
|
||||||
|
|
|
@ -8,7 +8,7 @@ from re import compile as re_compile
|
||||||
|
|
||||||
import plexdb_functions as plexdb
|
import plexdb_functions as plexdb
|
||||||
from downloadutils import DownloadUtils as DU
|
from downloadutils import DownloadUtils as DU
|
||||||
from utils import try_encode, escape_html
|
from utils import try_encode
|
||||||
from PlexAPI import API
|
from PlexAPI import API
|
||||||
from PlexFunctions import GetPlexMetadata
|
from PlexFunctions import GetPlexMetadata
|
||||||
from kodidb_functions import kodiid_from_filename
|
from kodidb_functions import kodiid_from_filename
|
||||||
|
@ -190,8 +190,16 @@ class Playlist_Item(object):
|
||||||
"""
|
"""
|
||||||
stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type]
|
stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type]
|
||||||
count = 0
|
count = 0
|
||||||
|
# Kodi indexes differently than Plex
|
||||||
for stream in self.xml[0][self.part]:
|
for stream in self.xml[0][self.part]:
|
||||||
if stream.attrib['streamType'] == stream_type:
|
if (stream.attrib['streamType'] == stream_type and
|
||||||
|
'key' in stream.attrib):
|
||||||
|
if count == kodi_stream_index:
|
||||||
|
return stream.attrib['id']
|
||||||
|
count += 1
|
||||||
|
for stream in self.xml[0][self.part]:
|
||||||
|
if (stream.attrib['streamType'] == stream_type and
|
||||||
|
'key' not in stream.attrib):
|
||||||
if count == kodi_stream_index:
|
if count == kodi_stream_index:
|
||||||
return stream.attrib['id']
|
return stream.attrib['id']
|
||||||
count += 1
|
count += 1
|
||||||
|
@ -208,7 +216,14 @@ class Playlist_Item(object):
|
||||||
stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type]
|
stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type]
|
||||||
count = 0
|
count = 0
|
||||||
for stream in self.xml[0][self.part]:
|
for stream in self.xml[0][self.part]:
|
||||||
if stream.attrib['streamType'] == stream_type:
|
if (stream.attrib['streamType'] == stream_type and
|
||||||
|
'key' in stream.attrib):
|
||||||
|
if stream.attrib['id'] == plex_stream_index:
|
||||||
|
return count
|
||||||
|
count += 1
|
||||||
|
for stream in self.xml[0][self.part]:
|
||||||
|
if (stream.attrib['streamType'] == stream_type and
|
||||||
|
'key' not in stream.attrib):
|
||||||
if stream.attrib['id'] == plex_stream_index:
|
if stream.attrib['id'] == plex_stream_index:
|
||||||
return count
|
return count
|
||||||
count += 1
|
count += 1
|
||||||
|
@ -308,8 +323,7 @@ def playlist_item_from_plex(plex_id):
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def playlist_item_from_xml(playlist, xml_video_element, kodi_id=None,
|
def playlist_item_from_xml(xml_video_element, kodi_id=None, kodi_type=None):
|
||||||
kodi_type=None):
|
|
||||||
"""
|
"""
|
||||||
Returns a playlist element for the playqueue using the Plex xml
|
Returns a playlist element for the playqueue using the Plex xml
|
||||||
|
|
||||||
|
@ -319,13 +333,9 @@ def playlist_item_from_xml(playlist, xml_video_element, kodi_id=None,
|
||||||
api = API(xml_video_element)
|
api = API(xml_video_element)
|
||||||
item.plex_id = api.plex_id()
|
item.plex_id = api.plex_id()
|
||||||
item.plex_type = api.plex_type()
|
item.plex_type = api.plex_type()
|
||||||
try:
|
# item.id will only be set if you passed in an xml_video_element from e.g.
|
||||||
item.id = xml_video_element.attrib['%sItemID' % playlist.kind]
|
# a playQueue
|
||||||
except KeyError:
|
item.id = api.item_id()
|
||||||
pass
|
|
||||||
item.guid = xml_video_element.attrib.get('guid')
|
|
||||||
if item.guid is not None:
|
|
||||||
item.guid = escape_html(item.guid)
|
|
||||||
if kodi_id is not None:
|
if kodi_id is not None:
|
||||||
item.kodi_id = kodi_id
|
item.kodi_id = kodi_id
|
||||||
item.kodi_type = kodi_type
|
item.kodi_type = kodi_type
|
||||||
|
@ -333,9 +343,12 @@ def playlist_item_from_xml(playlist, xml_video_element, kodi_id=None,
|
||||||
with plexdb.Get_Plex_DB() as plex_db:
|
with plexdb.Get_Plex_DB() as plex_db:
|
||||||
db_element = plex_db.getItem_byId(item.plex_id)
|
db_element = plex_db.getItem_byId(item.plex_id)
|
||||||
try:
|
try:
|
||||||
item.kodi_id, item.kodi_type = int(db_element[0]), db_element[4]
|
item.kodi_id, item.kodi_type = db_element[0], db_element[4]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
item.guid = api.guid_html_escaped()
|
||||||
|
item.playcount = api.viewcount()
|
||||||
|
item.offset = api.resume_point()
|
||||||
item.xml = xml_video_element
|
item.xml = xml_video_element
|
||||||
LOG.debug('Created new playlist item from xml: %s', item)
|
LOG.debug('Created new playlist item from xml: %s', item)
|
||||||
return item
|
return item
|
||||||
|
@ -420,7 +433,7 @@ def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
|
||||||
parameters=params)
|
parameters=params)
|
||||||
get_playlist_details_from_xml(playlist, xml)
|
get_playlist_details_from_xml(playlist, xml)
|
||||||
# Need to get the details for the playlist item
|
# Need to get the details for the playlist item
|
||||||
item = playlist_item_from_xml(playlist, xml[0])
|
item = playlist_item_from_xml(xml[0])
|
||||||
except (KeyError, IndexError, TypeError):
|
except (KeyError, IndexError, TypeError):
|
||||||
raise PlaylistError('Could not init Plex playlist with plex_id %s and '
|
raise PlaylistError('Could not init Plex playlist with plex_id %s and '
|
||||||
'kodi_item %s' % (plex_id, kodi_item))
|
'kodi_item %s' % (plex_id, kodi_item))
|
||||||
|
@ -484,8 +497,8 @@ def add_item_to_playlist(playlist, pos, kodi_id=None, kodi_type=None,
|
||||||
params['item'] = {'file': item.file}
|
params['item'] = {'file': item.file}
|
||||||
reply = js.playlist_insert(params)
|
reply = js.playlist_insert(params)
|
||||||
if reply.get('error') is not None:
|
if reply.get('error') is not None:
|
||||||
raise PlaylistError('Could not add item to playlist. Kodi reply. %s',
|
raise PlaylistError('Could not add item to playlist. Kodi reply. %s'
|
||||||
reply)
|
% reply)
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
@ -506,17 +519,16 @@ def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None):
|
||||||
# Will always put the new item at the end of the Plex playlist
|
# Will always put the new item at the end of the Plex playlist
|
||||||
xml = DU().downloadUrl(url, action_type="PUT")
|
xml = DU().downloadUrl(url, action_type="PUT")
|
||||||
try:
|
try:
|
||||||
|
xml[-1].attrib
|
||||||
|
except (TypeError, AttributeError, KeyError, IndexError):
|
||||||
|
raise PlaylistError('Could not add item %s to playlist %s'
|
||||||
|
% (kodi_item, playlist))
|
||||||
|
api = API(xml[-1])
|
||||||
item.xml = xml[-1]
|
item.xml = xml[-1]
|
||||||
item.id = xml[-1].attrib['%sItemID' % playlist.kind]
|
item.id = api.item_id()
|
||||||
except IndexError:
|
item.guid = api.guid_html_escaped()
|
||||||
LOG.info('Could not get playlist children. Adding a dummy')
|
item.offset = api.resume_point()
|
||||||
except (TypeError, AttributeError, KeyError):
|
item.playcount = api.viewcount()
|
||||||
raise PlaylistError('Could not add item %s to playlist %s',
|
|
||||||
kodi_item, playlist)
|
|
||||||
# Get the guid for this item
|
|
||||||
for plex_item in xml:
|
|
||||||
if plex_item.attrib['%sItemID' % playlist.kind] == item.id:
|
|
||||||
item.guid = escape_html(plex_item.attrib['guid'])
|
|
||||||
playlist.items.append(item)
|
playlist.items.append(item)
|
||||||
if pos == len(playlist.items) - 1:
|
if pos == len(playlist.items) - 1:
|
||||||
# Item was added at the end
|
# Item was added at the end
|
||||||
|
@ -555,7 +567,7 @@ def add_item_to_kodi_playlist(playlist, pos, kodi_id=None, kodi_type=None,
|
||||||
raise PlaylistError('Could not add item to playlist. Kodi reply. %s',
|
raise PlaylistError('Could not add item to playlist. Kodi reply. %s',
|
||||||
reply)
|
reply)
|
||||||
if xml_video_element is not None:
|
if xml_video_element is not None:
|
||||||
item = playlist_item_from_xml(playlist, xml_video_element)
|
item = playlist_item_from_xml(xml_video_element)
|
||||||
item.kodi_id = kodi_id
|
item.kodi_id = kodi_id
|
||||||
item.kodi_type = kodi_type
|
item.kodi_type = kodi_type
|
||||||
item.file = file
|
item.file = file
|
||||||
|
@ -646,7 +658,7 @@ def add_to_Kodi_playlist(playlist, xml_video_element):
|
||||||
|
|
||||||
Returns a Playlist_Item or raises PlaylistError
|
Returns a Playlist_Item or raises PlaylistError
|
||||||
"""
|
"""
|
||||||
item = playlist_item_from_xml(playlist, xml_video_element)
|
item = playlist_item_from_xml(xml_video_element)
|
||||||
if item.kodi_id:
|
if item.kodi_id:
|
||||||
json_item = {'%sid' % item.kodi_type: item.kodi_id}
|
json_item = {'%sid' % item.kodi_type: item.kodi_id}
|
||||||
else:
|
else:
|
||||||
|
@ -673,7 +685,7 @@ def add_listitem_to_Kodi_playlist(playlist, pos, listitem, file,
|
||||||
playlist.kodi_pl.add(url=file, listitem=listitem, index=pos)
|
playlist.kodi_pl.add(url=file, listitem=listitem, index=pos)
|
||||||
# We need to add this to our internal queue as well
|
# We need to add this to our internal queue as well
|
||||||
if xml_video_element is not None:
|
if xml_video_element is not None:
|
||||||
item = playlist_item_from_xml(playlist, xml_video_element)
|
item = playlist_item_from_xml(xml_video_element)
|
||||||
else:
|
else:
|
||||||
item = playlist_item_from_kodi(kodi_item)
|
item = playlist_item_from_kodi(kodi_item)
|
||||||
if file is not None:
|
if file is not None:
|
||||||
|
|
|
@ -75,7 +75,7 @@ COMPANION_PORT = int(_ADDON.getSetting('companionPort'))
|
||||||
PKC_MACHINE_IDENTIFIER = None
|
PKC_MACHINE_IDENTIFIER = None
|
||||||
|
|
||||||
# Minimal PKC version needed for the Kodi database - otherwise need to recreate
|
# Minimal PKC version needed for the Kodi database - otherwise need to recreate
|
||||||
MIN_DB_VERSION = '2.0.0'
|
MIN_DB_VERSION = '2.0.4'
|
||||||
|
|
||||||
# Database paths
|
# Database paths
|
||||||
_DB_VIDEO_VERSION = {
|
_DB_VIDEO_VERSION = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue