Merge branch 'beta-version'
This commit is contained in:
commit
ea7f730264
2 changed files with 106 additions and 44 deletions
18
README.md
18
README.md
|
@ -11,7 +11,12 @@
|
||||||
# PlexKodiConnect (PKC)
|
# PlexKodiConnect (PKC)
|
||||||
**Combine the best frontend media player Kodi with the best multimedia backend server Plex**
|
**Combine the best frontend media player Kodi with the best multimedia backend server Plex**
|
||||||
|
|
||||||
PKC combines the best of Kodi - ultra smooth navigation, beautiful and highly customizable user interfaces and playback of any file under the sun - and the Plex Media Server.
|
PKC synchronizes your media from your Plex server to the native Kodi database. Hence:
|
||||||
|
- Use virtually any other Kodi add-on
|
||||||
|
- Use any Kodi skin, completely customize Kodi's look
|
||||||
|
- Browse your media very fluently (cached artwork)
|
||||||
|
- Automatically get additional artwork (more than Plex offers)
|
||||||
|
- Use Plex features with a Kodi interface
|
||||||
|
|
||||||
Have a look at [some screenshots](https://github.com/croneter/PlexKodiConnect/wiki/Some-PKC-Screenshots) to see what's possible.
|
Have a look at [some screenshots](https://github.com/croneter/PlexKodiConnect/wiki/Some-PKC-Screenshots) to see what's possible.
|
||||||
|
|
||||||
|
@ -21,7 +26,6 @@ Unfortunately, the PKC Kodi repository had to move because it stopped working (t
|
||||||
|
|
||||||
### Content
|
### Content
|
||||||
* [**Download and Installation**](#download-and-installation)
|
* [**Download and Installation**](#download-and-installation)
|
||||||
* [**What does PKC do?**](#what-does-pkc-do)
|
|
||||||
* [**Warning**](#warning)
|
* [**Warning**](#warning)
|
||||||
* [**PKC Features**](#pkc-features)
|
* [**PKC Features**](#pkc-features)
|
||||||
* [**Additional Artwork**](#additional-artwork)
|
* [**Additional Artwork**](#additional-artwork)
|
||||||
|
@ -38,14 +42,6 @@ Install PKC via the PlexKodiConnect Kodi repository download button just below (
|
||||||
|----------------|--------------|
|
|----------------|--------------|
|
||||||
| [![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) |
|
| [![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) |
|
||||||
|
|
||||||
### What does PKC do?
|
|
||||||
PKC synchronizes your media from your Plex server to the native Kodi database. Hence:
|
|
||||||
- Use virtually any other Kodi add-on
|
|
||||||
- Use any Kodi skin, completely customize Kodi's look
|
|
||||||
- Browse your media at full speed (cached artwork)
|
|
||||||
- Automatically get additional artwork (more than Plex offers)
|
|
||||||
- Enjoy Plex features using the Kodi interface
|
|
||||||
|
|
||||||
### 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 ;-)).
|
||||||
|
|
||||||
|
@ -53,7 +49,7 @@ Some people argue that PKC is 'hacky' because of the way it directly accesses th
|
||||||
|
|
||||||
### PKC Features
|
### PKC Features
|
||||||
|
|
||||||
- Support for Kodi 18 Leia Alpha 3 (nightly versions are NOT supported!)
|
- Support for Kodi 18 Beta 1 (nightly versions are NOT supported!)
|
||||||
- Support for Kodi 17 Krypton
|
- Support for Kodi 17 Krypton
|
||||||
- [Amazon Alexa voice recognition](https://www.plex.tv/apps/streaming-devices/amazon-alexa)
|
- [Amazon Alexa voice recognition](https://www.plex.tv/apps/streaming-devices/amazon-alexa)
|
||||||
- [Cinema Trailers & Extras](https://support.plex.tv/articles/202934883-cinema-trailers-extras/)
|
- [Cinema Trailers & Extras](https://support.plex.tv/articles/202934883-cinema-trailers-extras/)
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Syncs Plex playlists <=> Kodi playlists with 3 main components:
|
:module: plexkodiconnect.playlists
|
||||||
|
:synopsis: This module syncs Plex playlists to Kodi playlists and vice-versa
|
||||||
|
:author: Croneter
|
||||||
|
|
||||||
kodi_playlist_monitor()
|
.. autoclass:: kodi_playlist_monitor
|
||||||
watchdog Observer checking whether Kodi playlists are changed
|
|
||||||
|
|
||||||
websocket(plex_id, status)
|
.. autoclass:: full_sync
|
||||||
Hit with websocket answers from our background sync
|
|
||||||
|
|
||||||
full_sync()
|
.. autoclass:: websocket
|
||||||
Triggers a full re-sync of playlists
|
|
||||||
|
|
||||||
PlaylistError is thrown if anything wierd happens
|
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import, division, unicode_literals
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
@ -22,10 +19,7 @@ from . import pms, db, kodi_pl, plex_pl
|
||||||
|
|
||||||
from ..watchdog import events
|
from ..watchdog import events
|
||||||
from ..plex_api import API
|
from ..plex_api import API
|
||||||
from .. import utils
|
from .. import utils, path_ops, variables as v, state
|
||||||
from .. import path_ops
|
|
||||||
from .. import variables as v
|
|
||||||
from .. import state
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
LOG = getLogger('PLEX.playlists')
|
LOG = getLogger('PLEX.playlists')
|
||||||
|
@ -47,11 +41,22 @@ IGNORE_KODI_PLAYLIST_CHANGE = list()
|
||||||
|
|
||||||
def kodi_playlist_monitor():
|
def kodi_playlist_monitor():
|
||||||
"""
|
"""
|
||||||
Monitors the Kodi playlist folder special://profile/playlist for the user.
|
Monitor for the Kodi playlist folder special://profile/playlist
|
||||||
Will thus catch all changes on the Kodi side of things.
|
|
||||||
|
|
||||||
Returns an watchdog Observer instance. Be sure to use
|
Monitors for all file changes and will thus catch all changes on the Kodi
|
||||||
observer.stop() (and maybe observer.join()) to shut down properly
|
side of things (as soon as the user saves a new or modified playlist). This
|
||||||
|
is accomplished by starting a PlaylistObserver with the
|
||||||
|
PlaylistEventhandler
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
PlaylistObserver
|
||||||
|
Returns an already started PlaylistObserver instance
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
Be sure to stop the returned PlaylistObserver with observer.stop()
|
||||||
|
(and maybe observer.join()) to shut down properly
|
||||||
"""
|
"""
|
||||||
event_handler = PlaylistEventhandler()
|
event_handler = PlaylistEventhandler()
|
||||||
observer = PlaylistObserver(timeout=FILESYSTEM_TIMEOUT)
|
observer = PlaylistObserver(timeout=FILESYSTEM_TIMEOUT)
|
||||||
|
@ -62,7 +67,26 @@ def kodi_playlist_monitor():
|
||||||
|
|
||||||
def websocket(plex_id, status):
|
def websocket(plex_id, status):
|
||||||
"""
|
"""
|
||||||
Hit by librarysync to process websocket messages concerning playlists
|
Call this function to process websocket messages from the PMS
|
||||||
|
|
||||||
|
Will use the playlist lock to process one single websocket message from
|
||||||
|
the PMS, and e.g. create or delete the corresponding Kodi playlist (if
|
||||||
|
applicable settings are set)
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
plex_id : unicode
|
||||||
|
The unqiue Plex id 'ratingKey' as received from the PMS
|
||||||
|
status : int
|
||||||
|
'state' as communicated by the PMS in the websocket message. This
|
||||||
|
function will then take the correct actions to process the message
|
||||||
|
* 0: 'created'
|
||||||
|
* 2: 'matching'
|
||||||
|
* 3: 'downloading'
|
||||||
|
* 4: 'loading'
|
||||||
|
* 5: 'finished'
|
||||||
|
* 6: 'analyzing'
|
||||||
|
* 9: 'deleted'
|
||||||
"""
|
"""
|
||||||
create = False
|
create = False
|
||||||
with state.LOCK_PLAYLISTS:
|
with state.LOCK_PLAYLISTS:
|
||||||
|
@ -110,18 +134,25 @@ def websocket(plex_id, status):
|
||||||
|
|
||||||
def full_sync():
|
def full_sync():
|
||||||
"""
|
"""
|
||||||
Full sync of playlists between Kodi and Plex. Returns True is successful,
|
Full sync of playlists between Kodi and Plex
|
||||||
False otherwise
|
|
||||||
|
Call to trigger a full sync both ways, e.g. on Kodi start-up. If issues
|
||||||
|
with a single playlist are encountered on either the Plex or Kodi side,
|
||||||
|
this particular playlist is omitted. Will use the playlist lock.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if successful, False otherwise (actually only if we failed to
|
||||||
|
fetch the PMS playlists)
|
||||||
"""
|
"""
|
||||||
LOG.info('Starting playlist full sync')
|
LOG.info('Starting playlist full sync')
|
||||||
with state.LOCK_PLAYLISTS:
|
with state.LOCK_PLAYLISTS:
|
||||||
|
# Need to lock because we're messing with playlists
|
||||||
return _full_sync()
|
return _full_sync()
|
||||||
|
|
||||||
|
|
||||||
def _full_sync():
|
def _full_sync():
|
||||||
"""
|
|
||||||
Need to lock because we're messing with playlists
|
|
||||||
"""
|
|
||||||
# Get all Plex playlists
|
# Get all Plex playlists
|
||||||
xml = pms.all_playlists()
|
xml = pms.all_playlists()
|
||||||
if xml is None:
|
if xml is None:
|
||||||
|
@ -205,8 +236,22 @@ def _full_sync():
|
||||||
|
|
||||||
def sync_kodi_playlist(path):
|
def sync_kodi_playlist(path):
|
||||||
"""
|
"""
|
||||||
Returns True if we should sync this Kodi playlist with path [unicode] to
|
Checks whether we should sync a specific Kodi playlist to Plex
|
||||||
Plex based on the playlist file name and the user settings, False otherwise
|
|
||||||
|
Will check the following conditions for one single Kodi playlist:
|
||||||
|
* Kodi mixed playlists return False
|
||||||
|
* Support of the file type of the playlist, e.g. m3u
|
||||||
|
* Whether filename matches user settings to sync, if enabled
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path : unicode
|
||||||
|
Absolute file path to the Kodi playlist in question
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if we should sync this Kodi playlist to Plex, False otherwise
|
||||||
"""
|
"""
|
||||||
if path.startswith(v.PLAYLIST_PATH_MIXED):
|
if path.startswith(v.PLAYLIST_PATH_MIXED):
|
||||||
return False
|
return False
|
||||||
|
@ -227,12 +272,32 @@ def sync_kodi_playlist(path):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def sync_plex_playlist(plex_id=None, xml=None, playlist=None):
|
def sync_plex_playlist(playlist=None, xml=None, plex_id=None):
|
||||||
"""
|
"""
|
||||||
Returns True if we should sync this specific Plex playlist due to the
|
Checks whether we should sync a specific Plex playlist to Kodi
|
||||||
user settings (including a disabled music library), False if not.
|
|
||||||
|
|
||||||
Pass in either the plex_id or an xml (where API(xml) will be used)
|
Will check the following conditions for one single Plex playlist:
|
||||||
|
* Plex music playlists return False if PKC audio sync is disabled
|
||||||
|
* Whether filename matches user settings to sync, if enabled
|
||||||
|
* False is returned if we could not retrieve more information about the
|
||||||
|
playlist if only the plex_id was given
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
Pass in either playlist, xml or plex_id (preferably in this order)
|
||||||
|
|
||||||
|
plex_id : unicode
|
||||||
|
Absolute file path to the Kodi playlist in question
|
||||||
|
xml : etree xml
|
||||||
|
PMS metadata for the Plex element in question. API(xml) instead of
|
||||||
|
the usual API(xml[0]) will be used!
|
||||||
|
playlist: PlayList
|
||||||
|
A PlayList instance with Playlist.plex_name and PlayList.kodi_type set
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if we should sync this Plex playlist to Kodi, False otherwise
|
||||||
"""
|
"""
|
||||||
if playlist:
|
if playlist:
|
||||||
# Mainly once we DELETED a Plex playlist that we're NOT supposed
|
# Mainly once we DELETED a Plex playlist that we're NOT supposed
|
||||||
|
@ -254,11 +319,11 @@ def sync_plex_playlist(plex_id=None, xml=None, playlist=None):
|
||||||
return False
|
return False
|
||||||
name = api.title()
|
name = api.title()
|
||||||
typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX[api.playlist_type()]
|
typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX[api.playlist_type()]
|
||||||
if not state.SYNC_SPECIFIC_PLEX_PLAYLISTS:
|
|
||||||
return True
|
|
||||||
if (not state.ENABLE_MUSIC and typus == v.PLEX_PLAYLIST_TYPE_AUDIO):
|
if (not state.ENABLE_MUSIC and typus == v.PLEX_PLAYLIST_TYPE_AUDIO):
|
||||||
LOG.debug('Not synching Plex audio playlist')
|
LOG.debug('Not synching Plex audio playlist')
|
||||||
return False
|
return False
|
||||||
|
if not state.SYNC_SPECIFIC_PLEX_PLAYLISTS:
|
||||||
|
return True
|
||||||
prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower()
|
prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower()
|
||||||
if name and name.lower().startswith(prefix):
|
if name and name.lower().startswith(prefix):
|
||||||
return True
|
return True
|
||||||
|
@ -274,10 +339,11 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
|
||||||
"""
|
"""
|
||||||
Dispatches events to the appropriate methods.
|
Dispatches events to the appropriate methods.
|
||||||
|
|
||||||
:param event:
|
Parameters
|
||||||
The event object representing the file system event.
|
----------
|
||||||
:type event:
|
:type event:
|
||||||
:class:`FileSystemEvent`
|
:class:`FileSystemEvent`
|
||||||
|
The event object representing the file system event.
|
||||||
"""
|
"""
|
||||||
path = event.dest_path if event.event_type == events.EVENT_TYPE_MOVED \
|
path = event.dest_path if event.event_type == events.EVENT_TYPE_MOVED \
|
||||||
else event.src_path
|
else event.src_path
|
||||||
|
|
Loading…
Reference in a new issue