Merge pull request #1405 from croneter/beta-version

Bump master for Phyton 2
This commit is contained in:
croneter 2021-03-14 14:29:10 +01:00 committed by GitHub
commit 808136bff8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 119 additions and 35 deletions

View file

@ -1,8 +1,8 @@
[![Kodi Leia stable version](https://img.shields.io/badge/Kodi_Leia_STABLE-latest-blue.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.STABLE.zip) [![Kodi Leia stable version](https://img.shields.io/badge/Kodi_Leia_STABLE-latest-blue.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.STABLE.zip)
[![Kodi Leia beta version](https://img.shields.io/badge/Kodi_Leia_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.BETA.zip) [![Kodi Leia beta version](https://img.shields.io/badge/Kodi_Leia_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.BETA.zip)
[![Kodi Matrix stable version](https://img.shields.io/badge/Kodi_Matrix_STABLE-latest-blue.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Matrix.STABLE.zip)
[![Kodi Matrix beta version](https://img.shields.io/badge/Kodi_Matrix_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Matrix.BETA.zip) [![Kodi Matrix beta version](https://img.shields.io/badge/Kodi_Matrix_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Matrix.BETA.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)
[![Forum](https://img.shields.io/badge/forum-plex-orange.svg?maxAge=60&style=flat)](https://forums.plex.tv/discussion/210023/plexkodiconnect-let-kodi-talk-to-your-plex) [![Forum](https://img.shields.io/badge/forum-plex-orange.svg?maxAge=60&style=flat)](https://forums.plex.tv/discussion/210023/plexkodiconnect-let-kodi-talk-to-your-plex)
@ -39,11 +39,7 @@ Unfortunately, the PKC Kodi repository had to move because it stopped working (t
### Download and Installation ### Download and Installation
Install PKC via the PlexKodiConnect Kodi repository download button just below (do NOT use the standard GitHub download!). Alternatively, add [https://croneter.github.io/pkc-source](https://croneter.github.io/pkc-source) as a new Kodi `Web server directory (HTTPS)` source. See the [github wiki installation manual](https://github.com/croneter/PlexKodiConnect/wiki/Installation) for a detailed guide. Please use the stable version except if you really know what you're doing. Kodi will update PKC automatically. Using the Kodi file manager, add [https://croneter.github.io/pkc-source](https://croneter.github.io/pkc-source) as a new Kodi `Web server directory (HTTPS)` source, then install the PlexKodiConnect repository from this new source "from ZIP file". See the [github wiki installation manual](https://github.com/croneter/PlexKodiConnect/wiki/Installation) for a detailed guide. Kodi will update PKC automatically.
| Stable version | Beta version |
|----------------|--------------|
| [![stable version](https://img.shields.io/badge/stable_version-latest-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-latest-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip) |
### Warning ### Warning
Use at your own risk! 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. Don't worry if you want Plex to manage all your media (like you should ;-)). Use at your own risk! 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. Don't worry if you want Plex to manage all your media (like you should ;-)).

View file

@ -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.12.16" provider-name="croneter"> <addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.12.19" 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" />
@ -83,7 +83,19 @@
<summary lang="lt_LT">Natūralioji „Plex“ integracija į „Kodi“</summary> <summary lang="lt_LT">Natūralioji „Plex“ integracija į „Kodi“</summary>
<description lang="lt_LT">Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika!</description> <description lang="lt_LT">Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika!</description>
<disclaimer lang="lt_LT">Naudokite savo pačių rizika</disclaimer> <disclaimer lang="lt_LT">Naudokite savo pačių rizika</disclaimer>
<news>version 2.12.16: <news>version 2.12.19:
- 2.12.17 and 2.12.18 for everyone
- Rename skip intro skin file
version 2.12.18 (beta only):
- Quickly sync recently watched items before synching the playstates of the entire Plex library
- Improve logging for websocket JSON loads
version 2.12.17 (beta only):
- Sync name and user rating of a TV show season to Kodi
- Fix rare TypeError: expected string or buffer on playback start
version 2.12.16:
- versions 2.12.14 and 2.12.15 for everyone - versions 2.12.14 and 2.12.15 for everyone
version 2.12.15 (beta only): version 2.12.15 (beta only):

View file

@ -1,3 +1,15 @@
version 2.12.19:
- 2.12.17 and 2.12.18 for everyone
- Rename skip intro skin file
version 2.12.18 (beta only):
- Quickly sync recently watched items before synching the playstates of the entire Plex library
- Improve logging for websocket JSON loads
version 2.12.17 (beta only):
- Sync name and user rating of a TV show season to Kodi
- Fix rare TypeError: expected string or buffer on playback start
version 2.12.16: version 2.12.16:
- versions 2.12.14 and 2.12.15 for everyone - versions 2.12.14 and 2.12.15 for everyone

View file

@ -270,6 +270,7 @@ class Show(TvShowMixin, ItemBase):
unique_ids.get('imdb', unique_ids.get('imdb',
unique_ids.get('tmdb'))) unique_ids.get('tmdb')))
class Season(TvShowMixin, ItemBase): class Season(TvShowMixin, ItemBase):
def add_update(self, xml, section_name=None, section_id=None, def add_update(self, xml, section_name=None, section_id=None,
children=None): children=None):
@ -279,7 +280,7 @@ class Season(TvShowMixin, ItemBase):
api = API(xml) api = API(xml)
if not self.sync_this_item(section_id or api.library_section_id()): if not self.sync_this_item(section_id or api.library_section_id()):
LOG.debug('Skipping sync of %s %s: %s - section %s not synched to ' LOG.debug('Skipping sync of %s %s: %s - section %s not synched to '
'Kodi', api.plex_type, api.plex_id, api.title(), 'Kodi', api.plex_type, api.plex_id, api.season_name(),
section_id or api.library_section_id()) section_id or api.library_section_id())
return return
plex_id = api.plex_id plex_id = api.plex_id
@ -317,15 +318,24 @@ class Season(TvShowMixin, ItemBase):
if key in artwork and artwork[key] == parent_artwork[key]: if key in artwork and artwork[key] == parent_artwork[key]:
del artwork[key] del artwork[key]
if update_item: if update_item:
LOG.info('UPDATE season plex_id %s - %s', plex_id, api.title()) LOG.info('UPDATE season plex_id %s - %s',
plex_id, api.season_name())
kodi_id = season['kodi_id'] kodi_id = season['kodi_id']
self.kodidb.update_season(kodi_id,
parent_id,
api.index(),
api.season_name(),
api.userrating() or None)
if app.SYNC.artwork: if app.SYNC.artwork:
self.kodidb.modify_artwork(artwork, self.kodidb.modify_artwork(artwork,
kodi_id, kodi_id,
v.KODI_TYPE_SEASON) v.KODI_TYPE_SEASON)
else: else:
LOG.info('ADD season plex_id %s - %s', plex_id, api.title()) LOG.info('ADD season plex_id %s - %s', plex_id, api.season_name())
kodi_id = self.kodidb.add_season(parent_id, api.index()) kodi_id = self.kodidb.add_season(parent_id,
api.index(),
api.season_name(),
api.userrating() or None)
if app.SYNC.artwork: if app.SYNC.artwork:
self.kodidb.add_artwork(artwork, self.kodidb.add_artwork(artwork,
kodi_id, kodi_id,

View file

@ -718,15 +718,32 @@ class KodiVideoDB(common.KodiDBBase):
self.cursor.execute('DELETE FROM sets WHERE idSet = ?', (set_id,)) self.cursor.execute('DELETE FROM sets WHERE idSet = ?', (set_id,))
@db.catch_operationalerrors @db.catch_operationalerrors
def add_season(self, showid, seasonnumber): def add_season(self, showid, seasonnumber, name, userrating):
""" """
Adds a TV show season to the Kodi video DB or simply returns the ID, Adds a TV show season to the Kodi video DB or simply returns the ID,
if there already is an entry in the DB if there already is an entry in the DB
""" """
self.cursor.execute('INSERT INTO seasons(idShow, season) VALUES (?, ?)', self.cursor.execute('''
(showid, seasonnumber)) INSERT INTO seasons(
idShow, season, name, userrating)
VALUES (?, ?, ?, ?)
''', (showid, seasonnumber, name, userrating))
return self.cursor.lastrowid return self.cursor.lastrowid
@db.catch_operationalerrors
def update_season(self, seasonid, showid, seasonnumber, name, userrating):
"""
Updates a TV show season with a certain seasonid
"""
self.cursor.execute('''
UPDATE seasons
SET idShow = ?,
season = ?,
name = ?,
userrating = ?
WHERE idSeason = ?
''', (showid, seasonnumber, name, userrating, seasonid))
@db.catch_operationalerrors @db.catch_operationalerrors
def add_uniqueid(self, *args): def add_uniqueid(self, *args):
""" """

View file

@ -289,7 +289,7 @@ class KodiMonitor(xbmc.Monitor):
LOG.debug('Detected different path') LOG.debug('Detected different path')
try: try:
tmp_plex_id = int(utils.REGEX_PLEX_ID.findall(path)[0]) tmp_plex_id = int(utils.REGEX_PLEX_ID.findall(path)[0])
except IndexError: except (IndexError, TypeError):
LOG.debug('No Plex id in path, need to init playqueue') LOG.debug('No Plex id in path, need to init playqueue')
initialize = True initialize = True
else: else:

View file

@ -137,7 +137,7 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread):
LOG.error('Could not entirely process section %s', section) LOG.error('Could not entirely process section %s', section)
self.successful = False self.successful = False
def threaded_get_generators(self, kinds, section_queue, all_items): def threaded_get_generators(self, kinds, section_queue, items):
""" """
Getting iterators is costly, so let's do it in a dedicated thread Getting iterators is costly, so let's do it in a dedicated thread
""" """
@ -154,17 +154,28 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread):
continue continue
section = sections.get_sync_section(section, section = sections.get_sync_section(section,
plex_type=kind[0]) plex_type=kind[0])
if self.repair or all_items: timestamp = section.last_sync - UPDATED_AT_SAFETY \
updated_at = None
else:
updated_at = section.last_sync - UPDATED_AT_SAFETY \
if section.last_sync else None if section.last_sync else None
if items == 'all':
updated_at = None
last_viewed_at = None
elif items == 'watched':
if not timestamp:
# No need to sync playstate updates since section
# has not yet been synched
continue
else:
updated_at = None
last_viewed_at = timestamp
elif items == 'updated':
updated_at = timestamp
last_viewed_at = None
try: try:
section.iterator = PF.get_section_iterator( section.iterator = PF.get_section_iterator(
section.section_id, section.section_id,
plex_type=section.plex_type, plex_type=section.plex_type,
updated_at=updated_at, updated_at=updated_at,
last_viewed_at=None) last_viewed_at=last_viewed_at)
except RuntimeError: except RuntimeError:
LOG.error('Sync at least partially unsuccessful!') LOG.error('Sync at least partially unsuccessful!')
LOG.error('Error getting section iterator %s', section) LOG.error('Error getting section iterator %s', section)
@ -195,19 +206,42 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread):
(v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_ARTIST), (v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_ARTIST),
(v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST), (v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST),
]) ])
# ADD NEW ITEMS # ADD NEW ITEMS
# We need to enforce syncing e.g. show before season before episode # We need to enforce syncing e.g. show before season before episode
bg.FunctionAsTask(self.threaded_get_generators, bg.FunctionAsTask(self.threaded_get_generators,
None, None,
kinds, section_queue, False).start() kinds,
section_queue,
items='all' if self.repair else 'updated').start()
# Do the heavy lifting # Do the heavy lifting
self.process_new_and_changed_items(section_queue, processing_queue) self.process_new_and_changed_items(section_queue, processing_queue)
common.update_kodi_library(video=True, music=True) common.update_kodi_library(video=True, music=True)
if self.should_cancel() or not self.successful: if self.should_cancel() or not self.successful:
return return
# In order to not delete all your songs again for playstate synch
if app.SYNC.enable_music:
kinds.extend([
(v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST),
])
# Update playstate progress since last sync - especially useful for
# users of very large libraries since this step is very fast
# These playstates will be synched twice
LOG.debug('Start synching playstate for last watched items')
bg.FunctionAsTask(self.threaded_get_generators,
None,
kinds,
section_queue,
items='watched').start()
self.processing_loop_playstates(section_queue)
if self.should_cancel() or not self.successful:
return
# Sync Plex playlists to Kodi and vice-versa # Sync Plex playlists to Kodi and vice-versa
if common.PLAYLIST_SYNC_ENABLED: if common.PLAYLIST_SYNC_ENABLED:
LOG.debug('Start playlist sync')
if self.show_dialog: if self.show_dialog:
if self.dialog: if self.dialog:
self.dialog.close() self.dialog.close()
@ -218,14 +252,9 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread):
return return
# SYNC PLAYSTATE of ALL items (otherwise we won't pick up on items that # SYNC PLAYSTATE of ALL items (otherwise we won't pick up on items that
# were set to unwatched). Also mark all items on the PMS to be able # were set to unwatched or changed user ratings). Also mark all items on
# to delete the ones still in Kodi # the PMS to be able to delete the ones still in Kodi
LOG.debug('Start synching playstate and userdata for every item') LOG.debug('Start synching playstate and userdata for every item')
if app.SYNC.enable_music:
# In order to not delete all your songs again
kinds.extend([
(v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST),
])
# Make sure we're not showing an item's title in the sync dialog # Make sure we're not showing an item's title in the sync dialog
if not self.show_dialog_userdata and self.dialog: if not self.show_dialog_userdata and self.dialog:
# Close the progress indicator dialog # Close the progress indicator dialog
@ -233,7 +262,9 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread):
self.dialog = None self.dialog = None
bg.FunctionAsTask(self.threaded_get_generators, bg.FunctionAsTask(self.threaded_get_generators,
None, None,
kinds, section_queue, True).start() kinds,
section_queue,
items='all').start()
self.processing_loop_playstates(section_queue) self.processing_loop_playstates(section_queue)
if self.should_cancel() or not self.successful: if self.should_cancel() or not self.successful:
return return

View file

@ -398,6 +398,12 @@ class Base(object):
""" """
return self.parent_index() return self.parent_index()
def season_name(self):
"""
Returns the season's name/title or None
"""
return self.xml.get('title')
def artist_name(self): def artist_name(self):
""" """
Returns the artist name for an album: first it attempts to return Returns the artist name for an album: first it attempts to return

View file

@ -16,7 +16,7 @@ def skip_intro(intros):
if start <= progress < end: if start <= progress < end:
in_intro = True in_intro = True
if in_intro and app.APP.skip_intro_dialog is None: if in_intro and app.APP.skip_intro_dialog is None:
app.APP.skip_intro_dialog = SkipIntroDialog('skip_intro.xml', app.APP.skip_intro_dialog = SkipIntroDialog('script-plex-skip_intro.xml',
v.ADDON_PATH, v.ADDON_PATH,
'default', 'default',
'1080i', '1080i',

View file

@ -177,9 +177,9 @@ class PMS_Websocket(WebSocket):
try: try:
message = loads(message) message = loads(message)
except ValueError: except ValueError as err:
LOG.error('%s: Error decoding message from websocket', LOG.error('%s: Error decoding message from websocket: %s',
self.__class__.__name__) self.__class__.__name__, err)
LOG.error(message) LOG.error(message)
return return
try: try: