Merge branch 'master' into translations

This commit is contained in:
tomkat83 2017-02-18 17:58:56 +01:00
commit 43ede54afe
9 changed files with 218 additions and 139 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect"
name="PlexKodiConnect"
version="1.5.13"
version="1.5.14"
provider-name="croneter">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
@ -22,10 +22,14 @@
</extension>
<extension point="xbmc.addon.metadata">
<summary lang="en">Native Integration of Plex into Kodi</summary>
<summary lang="en_gb">Native Integration of Plex into Kodi</summary>
<summary lang="en_us">Native Integration of Plex into Kodi</summary>
<summary lang="cs">Úplná integrace Plexu do Kodi</summary>
<summary lang="de">Komplette Integration von Plex in Kodi</summary>
<summary lang="es">Native Integration of Plex into Kodi</summary>
<description lang="en">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description>
<description lang="en_gb">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description>
<description lang="en_us">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description>
<description lang="cs">Připojte Kodi ke svému Plex Media Serveru. Tento doplněk předpokládá, že spravujete veškerá svá videa pomocí Plexu (nikoliv pomocí Kodi). Můžete přijít o data uložená ve video a hudební databázi Kodi (tento doplněk je přímo mění). Používejte na vlastní nebezpečí!</description>
<description lang="de">Verbindet Kodi mit deinem Plex Media Server. Dieses Addon geht davon aus, dass du all deine Videos mit Plex verwaltest (und keine direkt mit Kodi). Du wirst möglicherweise Daten verlieren, die bereits in der Kodi Video- und/oder Musik-Datenbank gespeichert sind (da dieses Addon beide Datenbanken direkt verändert). Verwende auf eigene Gefahr!</description>
<description lang="es">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description>

View file

@ -1,3 +1,10 @@
version 1.5.14 (beta only)
- Krypton: Fix ratings for episodes and TV shows
- Plex Companion: Fix KeyError for Plex Web
- Fix UnicodeDecodeError for non-ASCII filenames
- Hopefully fix items not marked as entirely watched after having seen >90%
- Code optimization
version 1.5.13 (beta only)
- New Spanish translation, thanks @bartolomesoriano
- Fix some possible connection issues

View file

@ -57,7 +57,7 @@ import variables as v
log = logging.getLogger("PLEX."+__name__)
REGEX_IMDB = re_compile(r'''/(tt\d+)''')
REGEX_TVDB = re_compile(r'''tvdb://(\d+)''')
REGEX_TVDB = re_compile(r'''thetvdb:\/\/(.+?)\?''')
###############################################################################

View file

@ -9,7 +9,8 @@ from xbmc import sleep
from utils import settings, ThreadMethodsAdditionalSuspend, ThreadMethods
from plexbmchelper import listener, plexgdm, subscribers, functions, \
httppersist, plexsettings
from PlexFunctions import ParseContainerKey
from PlexFunctions import ParseContainerKey, GetPlexMetadata
from PlexAPI import API
import player
from entrypoint import Plex_Node
from variables import KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE
@ -95,8 +96,16 @@ class PlexCompanion(Thread):
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
return
try:
playqueue = self.mgr.playqueue.get_playqueue_from_type(
KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
except KeyError:
# E.g. Plex web does not supply the media type
# Still need to figure out the type (video vs. music vs. pix)
xml = GetPlexMetadata(data['key'])
api = API(xml[0])
playqueue = self.mgr.playqueue.get_playqueue_from_type(
KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
self.mgr.playqueue.update_playqueue_from_PMS(
playqueue,
ID,

View file

@ -314,7 +314,7 @@ def GetPlexCollections(mediatype):
return collections
def GetPlexPlaylist(itemid, librarySectionUUID, mediatype='movie',
def init_plex_playqueue(itemid, librarySectionUUID, mediatype='movie',
trailers=False):
"""
Returns raw API metadata XML dump for a playlist with e.g. trailers.

View file

@ -6,6 +6,7 @@ import logging
from urllib import urlencode
from ntpath import dirname
from datetime import datetime
from xbmc import sleep
import artwork
from utils import tryEncode, tryDecode, settings, window, kodiSQL, \
@ -21,6 +22,7 @@ import variables as v
log = logging.getLogger("PLEX."+__name__)
MARK_PLAYED_AT = 0.90
###############################################################################
@ -159,13 +161,13 @@ class Items(object):
# If the playback was stopped, check whether we need to increment the
# playcount. PMS won't tell us the playcount via websockets
if item['state'] in ('stopped', 'ended'):
markPlayed = 0.90
complete = float(item['viewOffset']) / float(item['duration'])
log.info('Item %s stopped with completion rate %s percent.'
'Mark item played at %s percent.'
% (item['ratingKey'], str(complete), markPlayed), 1)
if complete >= markPlayed:
% (item['ratingKey'], str(complete), MARK_PLAYED_AT), 1)
if complete >= MARK_PLAYED_AT:
log.info('Marking as completely watched in Kodi', 1)
sleep(500)
try:
item['viewCount'] += 1
except TypeError:
@ -314,7 +316,8 @@ class Movies(Items):
# Update the movie entry
if v.KODIVERSION >= 17:
# update new ratings Kodi 17
ratingid = self.kodi_db.get_ratingid(movieid)
ratingid = self.kodi_db.get_ratingid(movieid,
v.KODI_TYPE_MOVIE)
self.kodi_db.update_ratings(movieid,
v.KODI_TYPE_MOVIE,
"default",
@ -322,7 +325,8 @@ class Movies(Items):
votecount,
ratingid)
# update new uniqueid Kodi 17
uniqueid = self.kodi_db.get_uniqueid(movieid)
uniqueid = self.kodi_db.get_uniqueid(movieid,
v.KODI_TYPE_MOVIE)
self.kodi_db.update_uniqueid(movieid,
v.KODI_TYPE_MOVIE,
imdb,
@ -512,8 +516,6 @@ class TVShows(Items):
if not itemid:
log.error("Cannot parse XML data for TV show")
return
# If the item already exist in the local Kodi DB we'll perform a full item update
# If the item doesn't exist, we'll add it to the database
update_item = True
force_episodes = False
plex_dbitem = plex_db.getItem_byId(itemid)
@ -547,6 +549,7 @@ class TVShows(Items):
title, sorttitle = API.getTitle()
plot = API.getPlot()
rating = API.getAudienceRating()
votecount = None
premieredate = API.getPremiereDate()
tvdb = API.getProvider('tvdb')
mpaa = API.getMpaa()
@ -594,33 +597,6 @@ class TVShows(Items):
if update_item:
log.info("UPDATE tvshow itemid: %s - Title: %s"
% (itemid, title))
if v.KODIVERSION >= 17:
# update new ratings Kodi 17
ratingid = self.kodi_db.get_ratingid(showid)
self.kodi_db.update_ratings(showid,
v.KODI_TYPE_SHOW,
"default",
rating,
None, # votecount
ratingid)
# update new uniqueid Kodi 17
uniqueid = self.kodi_db.get_uniqueid(showid)
self.kodi_db.update_uniqueid(showid,
v.KODI_TYPE_SHOW,
tvdb,
"tvdb",
uniqueid)
# Update the tvshow entry
query = ' '.join((
"UPDATE tvshow",
"SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,",
"c12 = ?, c13 = ?, c14 = ?, c15 = ?",
"WHERE idShow = ?"
))
kodicursor.execute(query, (title, plot, rating, premieredate, genre, title,
tvdb, mpaa, studio, sorttitle, showid))
# Add reference is idempotent; the call here updates also fileid
# and pathid when item is moved or renamed
plex_db.addReference(itemid,
@ -630,50 +606,60 @@ class TVShows(Items):
kodi_pathid=pathid,
checksum=checksum,
view_id=viewid)
##### OR ADD THE TVSHOW #####
else:
log.info("ADD tvshow itemid: %s - Title: %s" % (itemid, title))
if v.KODIVERSION >= 17:
# add new ratings Kodi 17
ratingid = self.kodi_db.create_entry_rating()
self.kodi_db.add_ratings(ratingid,
showid,
# update new ratings Kodi 17
rating_id = self.kodi_db.get_ratingid(showid, v.KODI_TYPE_SHOW)
self.kodi_db.update_ratings(showid,
v.KODI_TYPE_SHOW,
"default",
rating,
None) # votecount
# add new uniqueid Kodi 17
uniqueid = self.kodi_db.create_entry_uniqueid()
self.kodi_db.add_uniqueid(uniqueid,
showid,
votecount,
rating_id)
# update new uniqueid Kodi 17
uniqueid = self.kodi_db.get_uniqueid(showid, v.KODI_TYPE_SHOW)
self.kodi_db.update_uniqueid(showid,
v.KODI_TYPE_SHOW,
tvdb,
"tvdb")
query = ' '.join((
"UPDATE path",
"SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
"WHERE idPath = ?"
))
kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
# Create the tvshow entry
query = (
"tvdb",
uniqueid)
# Update the tvshow entry
query = '''
UPDATE tvshow
SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,
c12 = ?, c13 = ?, c14 = ?, c15 = ?
WHERE idShow = ?
'''
INSERT INTO tvshow(
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14, c15)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
kodicursor.execute(query, (title, plot, rating_id,
premieredate, genre, title, tvdb,
mpaa, studio, sorttitle, showid))
else:
# Update the tvshow entry
query = '''
UPDATE tvshow
SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,
c12 = ?, c13 = ?, c14 = ?, c15 = ?
WHERE idShow = ?
'''
)
kodicursor.execute(query, (showid, title, plot, rating, premieredate, genre,
title, tvdb, mpaa, studio, sorttitle))
kodicursor.execute(query, (title, plot, rating, premieredate,
genre, title, tvdb, mpaa, studio,
sorttitle, showid))
# OR ADD THE TVSHOW #####
else:
log.info("ADD tvshow itemid: %s - Title: %s" % (itemid, title))
query = '''
UPDATE path
SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?
WHERE idPath = ?
'''
kodicursor.execute(query, (toplevelpath,
"tvshows",
"metadata.local",
1,
toppathid))
# Link the path
query = "INSERT INTO tvshowlinkpath(idShow, idPath) values(?, ?)"
query = "INSERT INTO tvshowlinkpath(idShow, idPath) values (?, ?)"
kodicursor.execute(query, (showid, pathid))
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_SHOW,
@ -682,14 +668,49 @@ class TVShows(Items):
kodi_pathid=pathid,
checksum=checksum,
view_id=viewid)
if v.KODIVERSION >= 17:
# add new ratings Kodi 17
rating_id = self.kodi_db.create_entry_rating()
self.kodi_db.add_ratings(rating_id,
showid,
v.KODI_TYPE_SHOW,
"default",
rating,
votecount)
# add new uniqueid Kodi 17
self.kodi_db.add_uniqueid(self.kodi_db.create_entry_uniqueid(),
showid,
v.KODI_TYPE_SHOW,
tvdb,
"tvdb")
# Create the tvshow entry
query = '''
INSERT INTO tvshow(
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14,
c15)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
kodicursor.execute(query, (showid, title, plot, rating_id,
premieredate, genre, title, tvdb,
mpaa, studio, sorttitle))
else:
# Create the tvshow entry
query = '''
INSERT INTO tvshow(
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14,
c15)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
kodicursor.execute(query, (showid, title, plot, rating,
premieredate, genre, title, tvdb,
mpaa, studio, sorttitle))
# Update the path
query = ' '.join((
"UPDATE path",
"SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?, ",
"idParentPath = ?"
"WHERE idPath = ?"
))
query = '''
UPDATE path
SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?,
idParentPath = ?
WHERE idPath = ?
'''
kodicursor.execute(query, (path, None, None, 1, toppathid, pathid))
# Process cast
@ -707,12 +728,6 @@ class TVShows(Items):
tags.extend(collections)
self.kodi_db.addTags(showid, tags, "tvshow")
# if force_episodes:
# # We needed to recreate the show entry. Re-add episodes now.
# log.info("Repairing episodes for showid: %s %s" % (showid, title))
# all_episodes = embyserver.getEpisodesbyShow(itemid)
# self.added_episode(all_episodes['Items'], None)
@CatchExceptions(warnuser=True)
def add_updateSeason(self, item, viewtag=None, viewid=None):
API = PlexAPI.API(item)
@ -809,13 +824,13 @@ class TVShows(Items):
userdata = API.getUserData()
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
tvdb = API.getProvider('tvdb')
votecount = None
# item details
peoples = API.getPeople()
director = API.joinList(peoples['Director'])
writer = API.joinList(peoples['Writer'])
cast = API.joinList(peoples['Cast'])
producer = API.joinList(peoples['Producer'])
title, sorttitle = API.getTitle()
plot = API.getPlot()
rating = userdata['Rating']
@ -916,7 +931,23 @@ class TVShows(Items):
log.info("UPDATE episode itemid: %s" % (itemid))
# Update the movie entry
if v.KODIVERSION >= 17:
# Kodi Krypton
# update new ratings Kodi 17
ratingid = self.kodi_db.get_ratingid(episodeid,
v.KODI_TYPE_EPISODE)
self.kodi_db.update_ratings(episodeid,
v.KODI_TYPE_EPISODE,
"default",
rating,
votecount,
ratingid)
# update new uniqueid Kodi 17
uniqueid = self.kodi_db.get_uniqueid(episodeid,
v.KODI_TYPE_EPISODE)
self.kodi_db.update_uniqueid(episodeid,
v.KODI_TYPE_EPISODE,
tvdb,
"tvdb",
uniqueid)
query = '''
UPDATE episode
SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?,
@ -962,7 +993,20 @@ class TVShows(Items):
log.info("ADD episode itemid: %s - Title: %s" % (itemid, title))
# Create the episode entry
if v.KODIVERSION >= 17:
# Kodi Krypton
# add new ratings Kodi 17
rating_id = self.kodi_db.create_entry_rating()
self.kodi_db.add_ratings(rating_id,
episodeid,
v.KODI_TYPE_EPISODE,
"default",
rating,
votecount)
# add new uniqueid Kodi 17
self.kodi_db.add_uniqueid(self.kodi_db.create_entry_uniqueid(),
episodeid,
v.KODI_TYPE_EPISODE,
tvdb,
"tvdb")
query = '''
INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04,
c05, c09, c10, c12, c13, c14, idShow, c15, c16, c18,
@ -971,7 +1015,7 @@ class TVShows(Items):
?, ?)
'''
kodicursor.execute(query, (episodeid, fileid, title, plot,
rating, writer, premieredate, runtime, director, season,
rating_id, writer, premieredate, runtime, director, season,
episode, title, showid, airsBeforeSeason,
airsBeforeEpisode, playurl, pathid, seasonid,
userdata['UserRating']))
@ -1193,18 +1237,23 @@ class TVShows(Items):
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_SHOW)
log.info("Removed tvshow: %s." % kodi_id)
def removeSeason(self, kodiid):
def removeSeason(self, kodi_id):
kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiid, "season", kodicursor)
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
log.info("Removed season: %s." % kodiid)
self.artwork.deleteArtwork(kodi_id, "season", kodicursor)
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?",
(kodi_id,))
log.info("Removed season: %s." % kodi_id)
def removeEpisode(self, kodiid, fileid):
def removeEpisode(self, kodi_id, fileid):
kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiid, "episode", kodicursor)
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
self.artwork.deleteArtwork(kodi_id, "episode", kodicursor)
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?",
(kodi_id,))
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
log.info("Removed episode: %s." % kodiid)
if v.KODIVERSION >= 17:
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE)
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_EPISODE)
log.info("Removed episode: %s." % kodi_id)
class Music(Items):

View file

@ -1423,9 +1423,11 @@ class Kodidb_Functions():
def add_uniqueid(self, *args):
"""
Feed with:
uniqueid_id, media_id, media_type, value, type
type: e.g. 'imdb'
uniqueid_id: int
media_id: int
media_type: string
value: string
type: e.g. 'imdb' or 'tvdb'
"""
query = '''
INSERT INTO uniqueid(
@ -1434,9 +1436,12 @@ class Kodidb_Functions():
'''
self.cursor.execute(query, (args))
def get_uniqueid(self, media_id):
query = "SELECT uniqueid_id FROM uniqueid WHERE media_id = ?"
self.cursor.execute(query, (media_id,))
def get_uniqueid(self, kodi_id, kodi_type):
query = '''
SELECT uniqueid_id FROM uniqueid
WHERE media_id = ? AND media_type = ?
'''
self.cursor.execute(query, (kodi_id, kodi_type))
try:
uniqueid = self.cursor.fetchone()[0]
except TypeError:
@ -1465,9 +1470,12 @@ class Kodidb_Functions():
self.cursor.execute("select coalesce(max(rating_id),0) from rating")
return self.cursor.fetchone()[0] + 1
def get_ratingid(self, media_id):
query = "SELECT rating_id FROM rating WHERE media_id = ?"
self.cursor.execute(query, (media_id,))
def get_ratingid(self, kodi_id, kodi_type):
query = '''
SELECT rating_id FROM rating
WHERE media_id = ? AND media_type = ?
'''
self.cursor.execute(query, (kodi_id, kodi_type))
try:
ratingid = self.cursor.fetchone()[0]
except TypeError:

View file

@ -14,7 +14,7 @@ from utils import window, settings, tryEncode, tryDecode, language as lang
import downloadutils
from PlexAPI import API
from PlexFunctions import GetPlexPlaylist
from PlexFunctions import init_plex_playqueue
from PKC_listitem import PKC_ListItem as ListItem, convert_PKC_to_listitem
from playlist_func import add_item_to_kodi_playlist, \
get_playlist_details_from_xml, add_listitem_to_Kodi_playlist, \
@ -134,8 +134,7 @@ class PlaybackUtils():
else:
trailers = True
# Post to the PMS. REUSE THE PLAYQUEUE!
xml = GetPlexPlaylist(
plex_id,
xml = init_plex_playqueue(plex_id,
plex_lib_UUID,
mediatype=api.getType(),
trailers=trailers)

View file

@ -8,7 +8,7 @@ import xbmc
import xbmcgui
from utils import window, settings, language as lang, DateToKodi, \
getUnixTimestamp
getUnixTimestamp, tryDecode, tryEncode
import downloadutils
import plexdb_functions as plexdb
import kodidb_functions as kodidb
@ -48,7 +48,7 @@ class Player(xbmc.Player):
# Get current file (in utf-8!)
try:
currentFile = self.getPlayingFile()
currentFile = tryDecode(self.getPlayingFile())
xbmc.sleep(300)
except:
currentFile = ""
@ -56,7 +56,7 @@ class Player(xbmc.Player):
while not currentFile:
xbmc.sleep(100)
try:
currentFile = self.getPlayingFile()
currentFile = tryDecode(self.getPlayingFile())
except:
pass
if count == 20:
@ -71,11 +71,11 @@ class Player(xbmc.Player):
self.currentFile = currentFile
window('plex_lastPlayedFiled', value=currentFile)
# We may need to wait for info to be set in kodi monitor
itemId = window("plex_%s.itemid" % currentFile)
itemId = window("plex_%s.itemid" % tryEncode(currentFile))
count = 0
while not itemId:
xbmc.sleep(200)
itemId = window("plex_%s.itemid" % currentFile)
itemId = window("plex_%s.itemid" % tryEncode(currentFile))
if count == 5:
log.warn("Could not find itemId, cancelling playback report!")
return
@ -83,7 +83,7 @@ class Player(xbmc.Player):
log.info("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId))
plexitem = "plex_%s" % currentFile
plexitem = "plex_%s" % tryEncode(currentFile)
runtime = window("%s.runtime" % plexitem)
refresh_id = window("%s.refreshid" % plexitem)
playMethod = window("%s.playmethod" % plexitem)
@ -146,8 +146,10 @@ class Player(xbmc.Player):
# Get the current audio track and subtitles
if playMethod == "Transcode":
# property set in PlayUtils.py
postdata['AudioStreamIndex'] = window("%sAudioStreamIndex" % currentFile)
postdata['SubtitleStreamIndex'] = window("%sSubtitleStreamIndex" % currentFile)
postdata['AudioStreamIndex'] = window("%sAudioStreamIndex"
% tryEncode(currentFile))
postdata['SubtitleStreamIndex'] = window("%sSubtitleStreamIndex"
% tryEncode(currentFile))
else:
# Get the current kodi audio and subtitles and convert to plex equivalent
tracks_query = {
@ -385,15 +387,16 @@ class Player(xbmc.Player):
# Clean the WINDOW properties
for filename in self.played_info:
plex_item = 'plex_%s' % tryEncode(filename)
cleanup = (
'plex_%s.itemid' % filename,
'plex_%s.runtime' % filename,
'plex_%s.refreshid' % filename,
'plex_%s.playmethod' % filename,
'plex_%s.type' % filename,
'plex_%s.runtime' % filename,
'plex_%s.playcount' % filename,
'plex_%s.playlistPosition' % filename
'%s.itemid' % plex_item,
'%s.runtime' % plex_item,
'%s.refreshid' % plex_item,
'%s.playmethod' % plex_item,
'%s.type' % plex_item,
'%s.runtime' % plex_item,
'%s.playcount' % plex_item,
'%s.playlistPosition' % plex_item
)
for item in cleanup:
window(item, clear=True)