Fix episode widget resume not working (add-on paths)

- Hack alert, really...
- Need to reset the Kodi DB
This commit is contained in:
croneter 2018-05-26 18:54:20 +02:00
parent ac7b7bb96d
commit 5c33f3c02a
8 changed files with 97 additions and 42 deletions

View file

@ -99,14 +99,15 @@ class API(object):
""" """
return self.item.get('ratingKey') return self.item.get('ratingKey')
def path(self, force_first_media=True): def path(self, force_first_media=True, force_addon=False):
""" """
Returns a "fully qualified path": add-on paths or direct paths Returns a "fully qualified path": add-on paths or direct paths
depending on the current settings. Will NOT valide the playurl depending on the current settings. Will NOT valide the playurl
Returns unicode or None if something went wrong. Returns unicode or None if something went wrong.
""" """
filename = self.file_path(force_first_media=force_first_media) filename = self.file_path(force_first_media=force_first_media)
if not state.DIRECT_PATHS or self.plex_type() == v.PLEX_TYPE_CLIP: if (not state.DIRECT_PATHS or force_addon
or self.plex_type() == v.PLEX_TYPE_CLIP):
if filename and '/' in filename: if filename and '/' in filename:
filename = filename.rsplit('/', 1) filename = filename.rsplit('/', 1)
elif filename: elif filename:
@ -116,11 +117,14 @@ class API(object):
except (TypeError, IndexError): except (TypeError, IndexError):
filename = None filename = None
# Set plugin path and media flags using real filename # Set plugin path and media flags using real filename
path = ('plugin://%s/?plex_id=%s&plex_type=%s&mode=play&filename=%s' if self.plex_type() == v.PLEX_TYPE_EPISODE:
% (v.ADDON_TYPE[self.plex_type()], # need to include the plex show id in the path
self.plex_id(), path = ('plugin://plugin.video.plexkodiconnect.tvshows/%s/'
self.plex_type(), % self.grandparent_id())
filename)) else:
path = 'plugin://%s/' % v.ADDON_TYPE[self.plex_type()]
path = ('%s?plex_id=%s&plex_type=%s&mode=play&filename=%s'
% (path, self.plex_id(), self.plex_type(), filename))
else: else:
# Direct paths is set the Kodi way # Direct paths is set the Kodi way
path = self.validate_playurl(filename, path = self.validate_playurl(filename,

View file

@ -155,10 +155,7 @@ class ContextMenu(object):
v.KODI_PLAYLIST_TYPE_FROM_KODI_TYPE[self.kodi_type]) v.KODI_PLAYLIST_TYPE_FROM_KODI_TYPE[self.kodi_type])
playqueue.clear() playqueue.clear()
state.CONTEXT_MENU_PLAY = True state.CONTEXT_MENU_PLAY = True
handle = ('plugin://%s/?plex_id=%s&plex_type=%s&mode=play' handle = self.api.path(force_first_media=False, force_addon=True)
% (v.ADDON_TYPE[self.plex_type],
self.plex_id,
self.plex_type))
xbmc.executebuiltin('RunPlugin(%s)' % handle) xbmc.executebuiltin('RunPlugin(%s)' % handle)
def _extras(self): def _extras(self):

View file

@ -552,14 +552,7 @@ def getOnDeck(viewid, mediatype, tagname, limit):
listitem = api.create_listitem( listitem = api.create_listitem(
append_show_title=append_show_title, append_show_title=append_show_title,
append_sxxexx=append_sxxexx) append_sxxexx=append_sxxexx)
if directpaths: url = api.path()
url = api.file_path(force_first_media=True)
else:
url = ('plugin://%s.tvshows/?plex_id=%s&plex_type=%s&mode=play&filename=%s'
% (v.ADDON_ID,
api.plex_id(),
api.plex_type(),
api.file_name(force_first_media=True)))
if api.resume_point(): if api.resume_point():
listitem.setProperty('resumetime', str(api.resume_point())) listitem.setProperty('resumetime', str(api.resume_point()))
xbmcplugin.addDirectoryItem( xbmcplugin.addDirectoryItem(
@ -829,11 +822,7 @@ def __build_item(xml_element):
elif api.plex_type() == v.PLEX_TYPE_PHOTO: elif api.plex_type() == v.PLEX_TYPE_PHOTO:
url = api.get_picture_path() url = api.get_picture_path()
else: else:
url = 'plugin://%s/?plex_id=%s&plex_type=%s&mode=play&filename=%s' \ url = api.path()
% (v.ADDON_TYPE[api.plex_type()],
api.plex_id(),
api.plex_type(),
api.file_name(force_first_media=True))
if api.resume_point(): if api.resume_point():
listitem.setProperty('resumetime', str(api.resume_point())) listitem.setProperty('resumetime', str(api.resume_point()))
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,

View file

@ -147,21 +147,22 @@ class Items(object):
userdata['Resume'], userdata['Resume'],
userdata['Runtime'], userdata['Runtime'],
userdata['PlayCount'], userdata['PlayCount'],
userdata['LastPlayedDate']) userdata['LastPlayedDate'],
api.plex_type())
if v.KODIVERSION >= 17: if v.KODIVERSION >= 17:
self.kodi_db.update_userrating(db_item[0], self.kodi_db.update_userrating(db_item[0],
db_item[4], db_item[4],
userdata['UserRating']) userdata['UserRating'])
def updatePlaystate(self, mark_played, view_count, resume, duration, def updatePlaystate(self, mark_played, view_count, resume, duration,
file_id, lastViewedAt): file_id, lastViewedAt, plex_type):
""" """
Use with websockets, not xml Use with websockets, not xml
""" """
# If the playback was stopped, check whether we need to increment the # If the playback was stopped, check whether we need to increment the
# playcount. PMS won't tell us the playcount via websockets # playcount. PMS won't tell us the playcount via websockets
LOG.debug('Set playstate for file_id %s: viewcount: %s, resume: %s', LOG.debug('Playstate file_id %s: viewcount: %s, resume: %s, type: %s',
file_id, view_count, resume) file_id, view_count, resume, plex_type)
if mark_played: if mark_played:
LOG.info('Marking as completely watched in Kodi') LOG.info('Marking as completely watched in Kodi')
try: try:
@ -174,7 +175,8 @@ class Items(object):
resume, resume,
duration, duration,
view_count, view_count,
lastViewedAt) lastViewedAt,
plex_type)
class Movies(Items): class Movies(Items):
@ -448,7 +450,12 @@ class Movies(Items):
# 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
self.kodi_db.addPlaystate(fileid, resume, runtime, playcount, dateplayed) self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed,
v.PLEX_TYPE_MOVIE)
def remove(self, plex_id): def remove(self, plex_id):
""" """
@ -584,7 +591,8 @@ class TVShows(Items):
# Set plugin path # Set plugin path
toplevelpath = "plugin://%s.tvshows/" % v.ADDON_ID toplevelpath = "plugin://%s.tvshows/" % v.ADDON_ID
path = "%s%s/" % (toplevelpath, itemid) path = "%s%s/" % (toplevelpath, itemid)
toppathid = self.kodi_db.get_path(toplevelpath) # Do NOT set a parent id because addon-path cannot be "stacked"
toppathid = None
pathid = self.kodi_db.add_video_path(path, pathid = self.kodi_db.add_video_path(path,
date_added=api.date_created(), date_added=api.date_created(),
@ -989,7 +997,24 @@ class TVShows(Items):
resume, resume,
runtime, runtime,
playcount, playcount,
dateplayed) dateplayed,
None) # Do send None, we check here
if not state.DIRECT_PATHS:
# need to set a SECOND file entry for a path without plex show id
filename = api.file_name(force_first_media=True)
path = 'plugin://%s.tvshows/' % v.ADDON_ID
# Filename is exactly the same, WITH plex show id!
filename = ('%s%s/?plex_id=%s&plex_type=%s&mode=play&filename=%s'
% (path, series_id, itemid, v.PLEX_TYPE_EPISODE,
filename))
pathid = self.kodi_db.add_video_path(path)
fileid = self.kodi_db.add_file(filename, pathid, dateadded)
self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed,
None) # Do send None - 2nd entry
@catch_exceptions(warnuser=True) @catch_exceptions(warnuser=True)
def remove(self, plex_id): def remove(self, plex_id):
@ -1093,7 +1118,7 @@ class TVShows(Items):
Remove an episode, and episode only from the Kodi DB (not Plex DB) Remove an episode, and episode only from the Kodi DB (not Plex DB)
""" """
self.kodi_db.modify_people(kodi_id, v.KODI_TYPE_EPISODE) self.kodi_db.modify_people(kodi_id, v.KODI_TYPE_EPISODE)
self.kodi_db.remove_file(file_id) self.kodi_db.remove_file(file_id, plex_type=v.PLEX_TYPE_EPISODE)
self.artwork.delete_artwork(kodi_id, self.artwork.delete_artwork(kodi_id,
v.KODI_TYPE_EPISODE, v.KODI_TYPE_EPISODE,
self.kodicursor) self.kodicursor)

View file

@ -8,6 +8,7 @@ from sqlite3 import IntegrityError
import artwork import artwork
from utils import kodi_sql, try_decode, unix_timestamp, unix_date_to_kodi from utils import kodi_sql, try_decode, unix_timestamp, unix_date_to_kodi
import variables as v import variables as v
import state
############################################################################### ###############################################################################
@ -237,13 +238,31 @@ class KodiDBMethods(object):
show_id = None show_id = None
return show_id return show_id
def remove_file(self, file_id, remove_orphans=True): def remove_file(self, file_id, remove_orphans=True, plex_type=None):
""" """
Removes the entry for file_id from the files table. Will also delete Removes the entry for file_id from the files table. Will also delete
entries from the associated tables: bookmark, settings, streamdetails. entries from the associated tables: bookmark, settings, streamdetails.
If remove_orphans is true, this method will delete any orphaned path If remove_orphans is true, this method will delete any orphaned path
entries in the Kodi path table entries in the Kodi path table
Passing plex_type = v.PLEX_TYPE_EPISODE deletes any secondary files for
add-on paths
""" """
if not state.DIRECT_PATHS and plex_type == v.PLEX_TYPE_EPISODE:
# Hack for the 2 entries for episodes for addon paths
query = 'SELECT strFilename FROM files WHERE idFile = ? LIMIT 1'
self.cursor.execute(query, (file_id, ))
filename = self.cursor.fetchone()
if not filename:
LOG.error('Could not find file_id %s', file_id)
return
query = 'SELECT idFile FROM files WHERE strFilename = ? LIMIT 2'
self.cursor.execute(query, (filename[0], ))
file_ids = self.cursor.fetchall()
for new_id in file_ids:
self.remove_file(new_id[0], remove_orphans=remove_orphans)
return
self.cursor.execute('SELECT idPath FROM files WHERE idFile = ? LIMIT 1', self.cursor.execute('SELECT idPath FROM files WHERE idFile = ? LIMIT 1',
(file_id,)) (file_id,))
try: try:
@ -708,7 +727,29 @@ class KodiDBMethods(object):
return answ return answ
def addPlaystate(self, file_id, resume_seconds, total_seconds, playcount, def addPlaystate(self, file_id, resume_seconds, total_seconds, playcount,
dateplayed): dateplayed, plex_type):
if not state.DIRECT_PATHS and plex_type == v.PLEX_TYPE_EPISODE:
# Need to make sure to set a SECOND bookmark entry for another,
# second file_id that points to the path .tvshows instead of
# .tvshows/<plex show id/!
query = 'SELECT strFilename FROM files WHERE idFile = ? LIMIT 1'
self.cursor.execute(query, (file_id, ))
filename = self.cursor.fetchone()
if not filename:
LOG.error('Could not find fileid %s in Kodi DB', file_id)
raise RuntimeError
query = 'SELECT idFile FROM files WHERE strFilename = ? LIMIT 2'
self.cursor.execute(query, (filename[0], ))
file_ids = self.cursor.fetchall()
if len(file_ids) != 2:
LOG.error('Expected to find 2 file ids but found %s',
len(file_ids))
raise RuntimeError
for new_id in file_ids:
self.addPlaystate(new_id[0], resume_seconds, total_seconds,
playcount, dateplayed, None)
return
# Delete existing resume point # Delete existing resume point
self.cursor.execute('DELETE FROM bookmark WHERE idFile = ?', (file_id,)) self.cursor.execute('DELETE FROM bookmark WHERE idFile = ?', (file_id,))
# Set watched count # Set watched count

View file

@ -523,7 +523,8 @@ def _record_playstate(status, ended):
time, time,
totaltime, totaltime,
playcount, playcount,
last_played) last_played,
status['plex_type'])
# Hack to force "in progress" widget to appear if it wasn't visible before # Hack to force "in progress" widget to appear if it wasn't visible before
if (state.FORCE_RELOAD_SKIN and if (state.FORCE_RELOAD_SKIN and
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')): xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):

View file

@ -1357,12 +1357,14 @@ class LibrarySync(Thread):
item_fkt = getattr(itemtypes, item_fkt = getattr(itemtypes,
v.ITEMTYPE_FROM_KODITYPE[session['kodi_type']]) v.ITEMTYPE_FROM_KODITYPE[session['kodi_type']])
with item_fkt() as fkt: with item_fkt() as fkt:
plex_type = v.PLEX_TYPE_FROM_KODI_TYPE[session['kodi_type']]
fkt.updatePlaystate(mark_played, fkt.updatePlaystate(mark_played,
session['viewCount'], session['viewCount'],
resume, resume,
session['duration'], session['duration'],
session['file_id'], session['file_id'],
utils.unix_date_to_kodi(utils.unix_timestamp())) utils.unix_date_to_kodi(utils.unix_timestamp()),
plex_type)
def sync_fanart(self, missing_only=True, refresh=False): def sync_fanart(self, missing_only=True, refresh=False):
""" """

View file

@ -241,11 +241,7 @@ def _prep_playlist_stack(xml):
api.set_part_number(part) api.set_part_number(part)
if kodi_id is None: if kodi_id is None:
# Need to redirect again to PKC to conclude playback # Need to redirect again to PKC to conclude playback
path = ('plugin://%s/?plex_id=%s&plex_type=%s&mode=play&filename=%s' path = api.path()
% (v.ADDON_TYPE[api.plex_type()],
api.plex_id(),
api.plex_type(),
api.file_name(force_first_media=True)))
listitem = api.create_listitem() listitem = api.create_listitem()
listitem.setPath(try_encode(path)) listitem.setPath(try_encode(path))
else: else: