Merge branch 'beta-version'

This commit is contained in:
Croneter 2018-07-04 09:13:13 +02:00
commit 92f3a9fd63
16 changed files with 141 additions and 80 deletions

View file

@ -1,5 +1,5 @@
[![stable version](https://img.shields.io/badge/stable_version-2.1.3-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.2.6-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.2.7-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)
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.2.6" provider-name="croneter">
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.2.7" provider-name="croneter">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.requests" version="2.9.1" />
@ -67,7 +67,14 @@
<summary lang="ru_RU">Нативная интеграция сервера Plex в Kodi</summary>
<description lang="ru_RU">Подключите Kodi к своему серверу Plex. Плагин предполагает что вы управляете своими видео с помощью Plex (а не в Kodi). Вы можете потерять текущие базы данных музыки и видео в Kodi (так как плагин напрямую их изменяет). Используйте на свой страх и риск</description>
<disclaimer lang="ru_RU">Используйте на свой страх и риск</disclaimer>
<news>version 2.2.6 (beta only):
<news>version 2.2.7 (beta only):
- Allow to only sync specific Plex or Kodi playlists
- Don't show artwork sync progress, reduce setting-writes
- Fix playback sometimes not starting up
- Use __future__ for contextmenu.py
- Fix imports
version 2.2.6 (beta only):
- Fix default settings string, only show in English, hopefully fixes PKC loosing its settings
version 2.2.5 (beta only):

View file

@ -1,3 +1,10 @@
version 2.2.7 (beta only):
- Allow to only sync specific Plex or Kodi playlists
- Don't show artwork sync progress, reduce setting-writes
- Fix playback sometimes not starting up
- Use __future__ for contextmenu.py
- Fix imports
version 2.2.6 (beta only):
- Fix default settings string, only show in English, hopefully fixes PKC loosing its settings

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
###############################################################################
from __future__ import absolute_import, division, unicode_literals
from sys import listitem
from urllib import urlencode

View file

@ -169,9 +169,9 @@ class Main():
@staticmethod
def deviceid():
deviceId_old = pickler.pickl_window('plex_client_Id')
from clientinfo import getDeviceId
from resources.lib import clientinfo
try:
deviceId = getDeviceId(reset=True)
deviceId = clientinfo.getDeviceId(reset=True)
except Exception as e:
log.error('Failed to generate a new device Id: %s' % e)
utils.dialog('ok', utils.lang(29999), utils.lang(33032))

View file

@ -113,11 +113,21 @@ msgctxt "#30020"
msgid "Sync Plex playlists"
msgstr ""
# PKC settings sync options
msgctxt "#30021"
msgid "Only sync specific Plex playlists to Kodi"
msgstr ""
# PKC settings category
msgctxt "#30022"
msgid "Advanced"
msgstr ""
# PKC settings sync options
msgctxt "#30023"
msgid "Only sync specific Kodi playlists to Plex"
msgstr ""
msgctxt "#30024"
msgid "Username"
msgstr ""
@ -126,6 +136,16 @@ msgctxt "#30025"
msgid "Display message if PMS goes offline"
msgstr ""
# PKC settings sync options
msgctxt "#30026"
msgid "Prefix in Plex playlist name to trigger sync"
msgstr ""
# PKC settings sync options
msgctxt "#30027"
msgid "Prefix in Kodi playlist name to trigger sync"
msgstr ""
msgctxt "#30030"
msgid "Port Number"
msgstr ""

View file

@ -51,8 +51,6 @@ class Image_Cache_Thread(Thread):
suspended = self.suspended
queue = self.queue
sleep_between = self.sleep_between
counter = 0
set_zero = False
while not stopped():
# In the event the server goes offline
while suspended():
@ -66,14 +64,8 @@ class Image_Cache_Thread(Thread):
try:
url = queue.get(block=False)
except Empty:
if not set_zero and not xbmc.getCondVisibility(
'Window.IsVisible(DialogAddonSettings.xml)'):
# Avoid saving '0' all the time
set_zero = True
utils.settings('caching_artwork_count', value='0')
xbmc.sleep(1000)
continue
set_zero = False
if isinstance(url, ArtworkSyncMessage):
if state.IMAGE_SYNC_NOTIFICATIONS:
utils.dialog('notification',
@ -125,13 +117,6 @@ class Image_Cache_Thread(Thread):
# We did not even get a timeout
break
queue.task_done()
# Update the caching state in the PKC settings.
counter += 1
if (counter > 20 and not xbmc.getCondVisibility(
'Window.IsVisible(DialogAddonSettings.xml)')):
counter = 0
utils.settings('caching_artwork_count',
value=str(queue.qsize()))
# Sleep for a bit to reduce CPU strain
xbmc.sleep(sleep_between)
LOG.info("---===### Stopped Image_Cache_Thread ###===---")
@ -172,13 +157,10 @@ class Artwork():
connection.close()
if not artworks_to_cache:
LOG.info('Caching of major images to Kodi texture cache done')
# Set to "None"
utils.settings('caching_artwork_count', value=utils.lang(30069))
return
length = len(artworks_to_cache)
LOG.info('Caching has not been completed - caching %s major images',
length)
utils.settings('caching_artwork_count', value=str(length))
# Caching %s Plex images
self.queue.put(ArtworkSyncMessage(utils.lang(30006) % length))
for i, url in enumerate(artworks_to_cache):

View file

@ -31,7 +31,7 @@ def choose_pms_server():
"""
LOG.info("Choosing PMS server requested, starting")
import initialsetup
from . import initialsetup
setup = initialsetup.InitialSetup()
server = setup.pick_pms(showDialog=True)
if server is None:
@ -46,9 +46,8 @@ def choose_pms_server():
if not _log_out():
return
from utils import wipe_database
# Wipe Kodi and Plex database as well as playlists and video nodes
wipe_database()
utils.wipe_database()
# Log in again
_log_in()
@ -81,7 +80,7 @@ def toggle_plex_tv_sign_in():
utils.plex_command('PLEX_USERNAME', '')
else:
LOG.info('Login to plex.tv')
import initialsetup
from . import initialsetup
initialsetup.InitialSetup().plex_tv_sign_in()
utils.dialog('notification',
utils.lang(29999),
@ -180,10 +179,9 @@ def switch_plex_user():
if not _log_out():
return
# First remove playlists of old user
from utils import delete_playlists, delete_nodes
delete_playlists()
utils.delete_playlists()
# Remove video nodes
delete_nodes()
utils.delete_nodes()
_log_in()

View file

@ -48,7 +48,9 @@ STATE_SETTINGS = {
'forceReloadSkinOnPlaybackStop': 'FORCE_RELOAD_SKIN',
'fetch_pms_item_number': 'FETCH_PMS_ITEM_NUMBER',
'imageSyncNotifications': 'IMAGE_SYNC_NOTIFICATIONS',
'enablePlaylistSync': 'SYNC_PLAYLISTS'
'enablePlaylistSync': 'SYNC_PLAYLISTS',
'syncSpecificPlexPlaylists': 'SYNC_SPECIFIC_PLEX_PLAYLISTS',
'syncSpecificKodiPlaylists': 'SYNC_SPECIFIC_KODI_PLAYLISTS'
}
###############################################################################

View file

@ -48,8 +48,6 @@ class ThreadedProcessFanart(Thread):
stopped = self.stopped
suspended = self.suspended
queue = self.queue
counter = 0
set_zero = False
while not stopped():
# In the event the server goes offline
while suspended():
@ -63,14 +61,8 @@ class ThreadedProcessFanart(Thread):
try:
item = queue.get(block=False)
except Empty:
if not set_zero and not xbmc.getCondVisibility(
'Window.IsVisible(DialogAddonSettings.xml)'):
# Avoid saving '0' all the time
set_zero = True
utils.settings('fanarttv_lookups', value='0')
xbmc.sleep(200)
continue
set_zero = False
if isinstance(item, artwork.ArtworkSyncMessage):
if state.IMAGE_SYNC_NOTIFICATIONS:
utils.dialog('notification',
@ -90,11 +82,5 @@ class ThreadedProcessFanart(Thread):
LOG.debug('Done getting fanart for Plex id %s', item['plex_id'])
with plexdb.Get_Plex_DB() as plex_db:
plex_db.set_fanart_synched(item['plex_id'])
# Update the caching state in the PKC settings. Avoid saving '0'
counter += 1
if (counter > 20 and not xbmc.getCondVisibility(
'Window.IsVisible(DialogAddonSettings.xml)')):
counter = 0
utils.settings('fanarttv_lookups', value=str(queue.qsize()))
queue.task_done()
LOG.debug("---===### Stopped FanartSync ###===---")

View file

@ -63,8 +63,16 @@ def delete_plex_playlist(playlist):
entry in the Plex playlist table.
Returns None or raises PL.PlaylistError
"""
LOG.debug('Deleting playlist from PMS: %s', playlist)
PL.delete_playlist_from_pms(playlist)
if (state.SYNC_SPECIFIC_KODI_PLAYLISTS and
not sync_kodi_playlist(playlist.kodi_path)):
# We might have already synced this playlist BEFORE user chose to only
# sync specific playlists. Let's NOT delete all those playlists.
# However, delete it from our database of synced playlists.
LOG.debug('Not deleting playlist since user chose not to sync: %s',
playlist)
else:
LOG.debug('Deleting playlist from PMS: %s', playlist)
PL.delete_playlist_from_pms(playlist)
update_plex_table(playlist, delete=True)
@ -76,12 +84,20 @@ def create_kodi_playlist(plex_id=None, updated_at=None):
created in any case (not replaced). Thus make sure that the "same" playlist
is deleted from both disk and the Plex database.
Returns the playlist or raises PL.PlaylistError
Be aware that user settings will be checked whether this Plex playlist
should actually indeed be synced
"""
xml = PL.get_PMS_playlist(PL.Playlist_Object(), playlist_id=plex_id)
if xml is None:
LOG.error('Could not get Plex playlist %s', plex_id)
raise PL.PlaylistError('Could not get Plex playlist %s' % plex_id)
api = API(xml)
if state.SYNC_SPECIFIC_PLEX_PLAYLISTS:
prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower()
if api.title() and not api.title().lower().startswith(prefix):
LOG.debug('User chose to not sync playlist %s', api.title())
return
playlist = PL.Playlist_Object()
playlist.id = api.plex_id()
playlist.type = v.KODI_PLAYLIST_TYPE_FROM_PLEX[api.playlist_type()]
@ -122,14 +138,17 @@ def delete_kodi_playlist(playlist):
the Plex playlist table.
Returns None or raises PL.PlaylistError
"""
try:
path_ops.remove(playlist.kodi_path)
except (OSError, IOError) as err:
LOG.error('Could not delete Kodi playlist file %s. Error:\n %s: %s',
playlist, err.errno, err.strerror)
raise PL.PlaylistError('Could not delete %s' % playlist.kodi_path)
if not sync_kodi_playlist(playlist.kodi_path):
LOG.debug('Do not delete since we should not sync playlist %s',
playlist)
else:
update_plex_table(playlist, delete=True)
try:
path_ops.remove(playlist.kodi_path)
except (OSError, IOError) as err:
LOG.error('Could not delete Kodi playlist file %s. Error:\n%s: %s',
playlist, err.errno, err.strerror)
raise PL.PlaylistError('Could not delete %s' % playlist.kodi_path)
update_plex_table(playlist, delete=True)
def update_plex_table(playlist, delete=False):
@ -382,6 +401,8 @@ def _full_sync():
if extension not in SUPPORTED_FILETYPES:
continue
path = path_ops.path.join(root, file)
if not sync_kodi_playlist(path):
continue
kodi_hash = utils.generate_file_md5(path)
playlist = playlist_object_from_db(kodi_hash=kodi_hash)
playlist_2 = playlist_object_from_db(path=path)
@ -417,6 +438,25 @@ def _full_sync():
return True
def sync_kodi_playlist(path):
"""
Returns True if we should sync this Kodi playlist with path [unicode] to
Plex based on the playlist file name and the user settings, False otherwise
"""
if not state.SYNC_SPECIFIC_KODI_PLAYLISTS:
return True
playlist = PL.Playlist_Object()
try:
playlist.kodi_path = path
except PL.PlaylistError:
pass
else:
prefix = utils.settings('syncSpecificKodiPlaylistsPrefix').lower()
if playlist.kodi_filename.lower().startswith(prefix):
return True
return False
class PlaylistEventhandler(FileSystemEventHandler):
"""
PKC eventhandler to monitor Kodi playlists safed to disk
@ -444,6 +484,10 @@ class PlaylistEventhandler(FileSystemEventHandler):
if (not state.ENABLE_MUSIC and
event.src_path.startswith(v.PLAYLIST_PATH_MUSIC)):
return
path = event.dest_path if event.event_type == EVENT_TYPE_MOVED \
else event.src_path
if not sync_kodi_playlist(path):
return
_method_map = {
EVENT_TYPE_MODIFIED: self.on_modified,
EVENT_TYPE_MOVED: self.on_moved,

View file

@ -1228,46 +1228,49 @@ class API(object):
for entry in self.item.iterfind('./Media'):
count += 1
if (count > 1 and (
(self.plex_type() != 'clip' and
(self.plex_type() != v.PLEX_TYPE_CLIP and
utils.settings('bestQuality') == 'false')
or
(self.plex_type() == 'clip' and
(self.plex_type() == v.PLEX_TYPE_CLIP and
utils.settings('bestTrailer') == 'false'))):
# Several streams/files available.
dialoglist = []
for entry in self.item.iterfind('./Media'):
# Get additional info (filename / languages)
filename = None
if 'file' in entry[0].attrib:
filename = path_ops.path.basename(entry[0].attrib['file'])
option = utils.try_decode(entry[0].attrib['file'])
option = path_ops.path.basename(option)
else:
option = self.title() or ''
# Languages of audio streams
languages = []
for stream in entry[0]:
if (stream.attrib['streamType'] == '1' and
'language' in stream.attrib):
languages.append(stream.attrib['language'])
language = utils.try_decode(stream.attrib['language'])
languages.append(language)
languages = ', '.join(languages)
if filename:
option = utils.try_encode(filename)
if languages:
if option:
option = '%s (%s): ' % (option,
utils.try_encode(languages))
option = '%s (%s): ' % (option, languages)
else:
option = '%s: ' % utils.try_encode(languages)
option = '%s: ' % languages
else:
option = '%s ' % option
if 'videoResolution' in entry.attrib:
option = '%s%sp ' % (option,
entry.get('videoResolution'))
res = utils.try_decode(entry['videoResolution'])
option = '%s%sp ' % (option, res)
if 'videoCodec' in entry.attrib:
option = '%s%s' % (option,
entry.get('videoCodec'))
codec = utils.try_decode(entry['videoCodec'])
option = '%s%s' % (option, codec)
option = option.strip() + ' - '
if 'audioProfile' in entry.attrib:
option = '%s%s ' % (option,
entry.get('audioProfile'))
profile = utils.try_decode(entry['audioProfile'])
option = '%s%s ' % (option, profile)
if 'audioCodec' in entry.attrib:
option = '%s%s ' % (option,
entry.get('audioCodec'))
codec = utils.try_decode(entry['audioCodec'])
option = '%s%s ' % (option, codec)
option = utils.try_encode(option.strip())
dialoglist.append(option)
media = utils.dialog('select', 'Select stream', dialoglist)
else:

View file

@ -57,6 +57,14 @@ class Service():
utils.settings('syncThreadNumber'))
LOG.info('Playlist m3u encoding: %s', v.M3U_ENCODING)
LOG.info("Full sys.argv received: %s", sys.argv)
LOG.info('Synching only specific Kodi playlists: %s',
utils.settings('syncSpecificKodiPlaylists') == 'true')
LOG.info('Kodi playlist prefix: %s',
utils.settings('syncSpecificKodiPlaylistsPrefix'))
LOG.info('Synching only specific Plex playlists: %s',
utils.settings('syncSpecificPlexPlaylistsPrefix') == 'true')
LOG.info('Play playlist prefix: %s',
utils.settings('syncSpecificPlexPlaylistsPrefix'))
self.monitor = xbmc.Monitor()
# Load/Reset PKC entirely - important for user/Kodi profile switch
initialsetup.reload_pkc()

View file

@ -55,6 +55,10 @@ SYNC_DIALOG = True
IMAGE_SYNC_NOTIFICATIONS = True
# Sync playlists from Plex to Kodi and vice-versa?
SYNC_PLAYLISTS = True
# Only sync specific Plex playlists to Kodi?
SYNC_SPECIFIC_PLEX_PLAYLISTS = False
# Only sync specific Kodi playlists to Plex?
SYNC_SPECIFIC_KODI_PLAYLISTS = False
# Is synching of Plex music enabled?
ENABLE_MUSIC = True
# How often shall we sync?

View file

@ -464,9 +464,6 @@ def wipe_database():
cursor.execute("DELETE FROM %s" % table_name)
connection.commit()
cursor.close()
# Reset the artwork sync status in the PKC settings
settings('caching_artwork_count', value='unknown')
settings('fanarttv_lookups', value='unknown')
# reset the install run flag
settings('SyncInstallRunDone', value="false")

View file

@ -57,12 +57,18 @@
<category label="30506"><!-- Sync Options -->
<setting type="lsep" label="30537" /><!-- Restart if you make changes -->
<setting type="sep" />
<setting id="enablePlaylistSync" type="bool" label="30020" default="true" visible="true"/><!-- Sync Plex playlists -->
<setting id="fullSyncInterval" type="number" label="39053" default="60" option="int" />
<setting id="dbSyncScreensaver" type="bool" label="39062" default="false" /><!--Sync when screensaver is deactivated-->
<setting id="dbSyncIndicator" label="30507" type="bool" default="true" /><!-- show syncing progress -->
<setting id="syncThreadNumber" type="slider" label="39003" default="10" option="int" range="1,1,20"/><!-- Number of simultaneous download threads -->
<setting id="limitindex" type="number" label="30515" default="200" option="int" /><!-- Maximum items to request from the server at once -->
<setting type="lsep" label="$LOCALIZE[136]" /><!-- Playlists -->
<setting type="sep" />
<setting id="enablePlaylistSync" type="bool" label="30020" default="true" visible="true"/><!-- Sync Plex playlists -->
<setting id="syncSpecificKodiPlaylists" type="bool" label="30023" default="false" visible="true"/><!-- Only sync specific Kodi playlists to Plex -->
<setting id="syncSpecificKodiPlaylistsPrefix" type="text" label="30027" default="sync_" visible="eq(-1,true)"/><!-- Prefix in Kodi playlist name to trigger sync -->
<setting id="syncSpecificPlexPlaylists" type="bool" label="30021" default="false" visible="true"/><!-- Only sync specific Plex playlists to Kodi -->
<setting id="syncSpecificPlexPlaylistsPrefix" type="text" label="30026" default="sync_" visible="eq(-1,true)" /><!-- Prefix in Plex playlist name to trigger sync -->
<setting type="sep" />
<setting type="lsep" label="39052" /><!-- Background Sync -->
<setting id="enableBackgroundSync" type="bool" label="39026" default="true" visible="true"/>
@ -130,10 +136,6 @@
<setting id="imageSyncNotifications" label="30008" type="bool" default="true" /><!-- Enable notifications for image caching -->
<setting id="imageSyncDuringPlayback" label="30009" type="bool" default="true" /><!-- Enable image caching during Kodi playback (restart Kodi!) -->
<setting label="39020" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=texturecache)" option="close" /> <!-- Cache all images to Kodi texture cache now -->
<setting type="sep" />
<setting type="lsep" label="30010" /><!-- Approximate progress -->
<setting id="caching_artwork_count" label="30011" type="text" default="unknown" enable="false" visible="eq(-8,true)"/><!-- Plex artwork (posters and backgrounds) left to cache: -->
<setting id="fanarttv_lookups" label="30015" type="text" default="unknown" enable="false" visible="eq(-8,true)"/><!-- Movie and show FanartTV lookups left to do: -->
</category>
<!--
<category label="30235" visible="false">