mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2025-04-12 13:33:48 +00:00
Initial work on Kodi 19 (and Python 3) support
This commit is contained in:
parent
898b0d1faf
commit
a51bf9c2cc
68 changed files with 403 additions and 339 deletions
1
.env
Normal file
1
.env
Normal file
|
@ -0,0 +1 @@
|
|||
PYTHONPATH=jellyfin_kodi
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
*.pyo
|
||||
__pycache__/
|
||||
__local__/
|
||||
machine_guid
|
||||
/resources/media/Thumbs.db
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
<import addon="xbmc.python" version="2.25.0"/>
|
||||
<import addon="script.module.requests" version="2.22.0"/>
|
||||
<import addon="script.module.dateutil" version="2.7.3"/>
|
||||
<import addon="script.module.six" />
|
||||
<import addon="script.module.kodi-six" />
|
||||
<import addon="script.module.addon.signals" version="0.0.1"/>
|
||||
</requires>
|
||||
<extension point="xbmc.python.pluginsource"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,13 +7,12 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
#################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi')).decode('utf-8')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi'))
|
||||
|
||||
sys.path.insert(0, __base__)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,13 +7,12 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
#################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi')).decode('utf-8')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi'))
|
||||
|
||||
sys.path.insert(0, __base__)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,13 +7,12 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
#################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi')).decode('utf-8')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi'))
|
||||
|
||||
sys.path.insert(0, __base__)
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcaddon, xbmcvfs
|
||||
|
||||
from helper import translate, window, settings, addon_id, dialog
|
||||
from helper.utils import create_id
|
||||
|
@ -63,7 +62,7 @@ def get_device_name():
|
|||
Otherwise fallback to the Kodi device name.
|
||||
'''
|
||||
if not settings('deviceNameOpt.bool'):
|
||||
device_name = xbmc.getInfoLabel('System.FriendlyName').decode('utf-8')
|
||||
device_name = xbmc.getInfoLabel('System.FriendlyName')
|
||||
else:
|
||||
device_name = settings('deviceName')
|
||||
device_name = device_name.replace("\"", "_")
|
||||
|
@ -86,7 +85,7 @@ def get_device_id(reset=False):
|
|||
if client_id:
|
||||
return client_id
|
||||
|
||||
directory = xbmc.translatePath('special://profile/addon_data/plugin.video.jellyfin/').decode('utf-8')
|
||||
directory = xbmc.translatePath('special://profile/addon_data/plugin.video.jellyfin/')
|
||||
|
||||
if not xbmcvfs.exists(directory):
|
||||
xbmcvfs.mkdir(directory)
|
||||
|
@ -98,7 +97,7 @@ def get_device_id(reset=False):
|
|||
if not client_id or reset:
|
||||
LOG.info("Generating a new GUID.")
|
||||
|
||||
client_id = str("%012X" % create_id())
|
||||
client_id = str(create_id())
|
||||
file_guid = xbmcvfs.File(jellyfin_guid, 'w')
|
||||
file_guid.write(client_id)
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
import client
|
||||
from database import get_credentials, save_credentials
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
#################################################################################################
|
||||
|
||||
import datetime
|
||||
|
@ -8,10 +8,10 @@ import json
|
|||
import os
|
||||
import sqlite3
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
from six import text_type
|
||||
|
||||
import jellyfin_db
|
||||
from database import jellyfin_db
|
||||
from helper import translate, settings, window, dialog
|
||||
from objects import obj
|
||||
|
||||
|
@ -22,9 +22,6 @@ LOG = logging.getLogger("JELLYFIN." + __name__)
|
|||
#################################################################################################
|
||||
|
||||
|
||||
UNICODE = type(u"")
|
||||
|
||||
|
||||
class Database(object):
|
||||
|
||||
''' This should be called like a context.
|
||||
|
@ -76,7 +73,7 @@ class Database(object):
|
|||
|
||||
def _get_database(self, path, silent=False):
|
||||
|
||||
path = xbmc.translatePath(path).decode('utf-8')
|
||||
path = xbmc.translatePath(path)
|
||||
|
||||
if not silent:
|
||||
|
||||
|
@ -104,7 +101,7 @@ class Database(object):
|
|||
xbmc.executebuiltin('UpdateLibrary(video)')
|
||||
xbmc.sleep(200)
|
||||
|
||||
databases = xbmc.translatePath("special://database/").decode('utf-8')
|
||||
databases = xbmc.translatePath("special://database/")
|
||||
types = {
|
||||
'video': "MyVideos",
|
||||
'music': "MyMusic",
|
||||
|
@ -118,19 +115,19 @@ class Database(object):
|
|||
|
||||
if (file.startswith(database) and not file.endswith('-wal') and not file.endswith('-shm') and not file.endswith('db-journal')):
|
||||
|
||||
st = xbmcvfs.Stat(databases + file.decode('utf-8'))
|
||||
st = xbmcvfs.Stat(databases + file)
|
||||
modified_int = st.st_mtime()
|
||||
LOG.debug("Database detected: %s time: %s", file.decode('utf-8'), modified_int)
|
||||
LOG.debug("Database detected: %s time: %s", file, modified_int)
|
||||
|
||||
if modified_int > modified['time']:
|
||||
|
||||
modified['time'] = modified_int
|
||||
modified['file'] = file.decode('utf-8')
|
||||
modified['file'] = file
|
||||
|
||||
LOG.info("Discovered database: %s", modified)
|
||||
self.discovered_file = modified['file']
|
||||
|
||||
return xbmc.translatePath("special://database/%s" % modified['file']).decode('utf-8')
|
||||
return xbmc.translatePath("special://database/%s" % modified['file'])
|
||||
|
||||
def _sql(self, file):
|
||||
|
||||
|
@ -251,7 +248,7 @@ def reset():
|
|||
if dialog("yesno", heading="{jellyfin}", line1=translate(33086)):
|
||||
reset_artwork()
|
||||
|
||||
addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8')
|
||||
addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/")
|
||||
|
||||
if dialog("yesno", heading="{jellyfin}", line1=translate(33087)):
|
||||
|
||||
|
@ -317,17 +314,17 @@ def reset_artwork():
|
|||
|
||||
''' Remove all existing texture.
|
||||
'''
|
||||
thumbnails = xbmc.translatePath('special://thumbnails/').decode('utf-8')
|
||||
thumbnails = xbmc.translatePath('special://thumbnails/')
|
||||
|
||||
if xbmcvfs.exists(thumbnails):
|
||||
dirs, ignore = xbmcvfs.listdir(thumbnails)
|
||||
|
||||
for directory in dirs:
|
||||
ignore, thumbs = xbmcvfs.listdir(os.path.join(thumbnails, directory.decode('utf-8')))
|
||||
ignore, thumbs = xbmcvfs.listdir(os.path.join(thumbnails, directory))
|
||||
|
||||
for thumb in thumbs:
|
||||
LOG.debug("DELETE thumbnail %s", thumb)
|
||||
xbmcvfs.delete(os.path.join(thumbnails, directory.decode('utf-8'), thumb.decode('utf-8')))
|
||||
xbmcvfs.delete(os.path.join(thumbnails, directory, thumb))
|
||||
|
||||
with Database('texture') as texdb:
|
||||
texdb.cursor.execute("SELECT tbl_name FROM sqlite_master WHERE type='table'")
|
||||
|
@ -343,7 +340,7 @@ def reset_artwork():
|
|||
|
||||
def get_sync():
|
||||
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/")
|
||||
|
||||
if not xbmcvfs.exists(path):
|
||||
xbmcvfs.mkdirs(path)
|
||||
|
@ -364,7 +361,7 @@ def get_sync():
|
|||
|
||||
def save_sync(sync):
|
||||
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/")
|
||||
|
||||
if not xbmcvfs.exists(path):
|
||||
xbmcvfs.mkdirs(path)
|
||||
|
@ -373,14 +370,14 @@ def save_sync(sync):
|
|||
|
||||
with open(os.path.join(path, 'sync.json'), 'wb') as outfile:
|
||||
data = json.dumps(sync, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
if isinstance(data, UNICODE):
|
||||
if isinstance(data, text_type):
|
||||
data = data.encode('utf-8')
|
||||
outfile.write(data)
|
||||
|
||||
|
||||
def get_credentials():
|
||||
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/")
|
||||
|
||||
if not xbmcvfs.exists(path):
|
||||
xbmcvfs.mkdirs(path)
|
||||
|
@ -424,14 +421,14 @@ def get_credentials():
|
|||
|
||||
def save_credentials(credentials):
|
||||
credentials = credentials or {}
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/")
|
||||
|
||||
if not xbmcvfs.exists(path):
|
||||
xbmcvfs.mkdirs(path)
|
||||
try:
|
||||
with open(os.path.join(path, 'data.json'), 'wb') as outfile:
|
||||
data = json.dumps(credentials, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
if isinstance(data, UNICODE):
|
||||
if isinstance(data, text_type):
|
||||
data = data.encode('utf-8')
|
||||
outfile.write(data)
|
||||
except Exception:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import queries as QU
|
||||
from database import queries as QU
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
get_item = """
|
||||
SELECT kodi_id, kodi_fileid, kodi_pathid, parent_id, media_type,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from serverconnect import ServerConnect
|
||||
from usersconnect import UsersConnect
|
||||
from loginmanual import LoginManual
|
||||
from servermanual import ServerManual
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from .serverconnect import ServerConnect
|
||||
from .usersconnect import UsersConnect
|
||||
from .loginmanual import LoginManual
|
||||
from .servermanual import ServerManual
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmcgui, xbmcaddon
|
||||
|
||||
from helper import window, addon_id
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
from six import iteritems
|
||||
from kodi_six import xbmcgui, xbmcaddon
|
||||
|
||||
from helper import translate, addon_id
|
||||
|
||||
|
@ -36,7 +37,7 @@ class LoginManual(xbmcgui.WindowXMLDialog):
|
|||
|
||||
def set_args(self, **kwargs):
|
||||
# connect_manager, user_image, servers
|
||||
for key, value in kwargs.iteritems():
|
||||
for key, value in iteritems(kwargs):
|
||||
setattr(self, key, value)
|
||||
|
||||
def is_logged_in(self):
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from kodi_six import xbmc, xbmcgui
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from six import iteritems
|
||||
from kodi_six import xbmc, xbmcgui
|
||||
|
||||
from helper import translate
|
||||
from jellyfin.connection_manager import CONNECTION_STATE
|
||||
|
@ -44,7 +45,7 @@ class ServerConnect(xbmcgui.WindowXMLDialog):
|
|||
|
||||
def set_args(self, **kwargs):
|
||||
# connect_manager, user_image, servers
|
||||
for key, value in kwargs.iteritems():
|
||||
for key, value in iteritems(kwargs):
|
||||
setattr(self, key, value)
|
||||
|
||||
def is_server_selected(self):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -6,8 +7,8 @@ import logging
|
|||
import os
|
||||
import re
|
||||
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
from six import iteritems
|
||||
from kodi_six import xbmcgui, xbmcaddon
|
||||
|
||||
from helper import translate, addon_id
|
||||
from jellyfin.connection_manager import CONNECTION_STATE
|
||||
|
@ -28,7 +29,7 @@ ERROR = {
|
|||
}
|
||||
|
||||
# https://stackoverflow.com/a/17871737/1035647
|
||||
_IPV6_PATTERN = "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
|
||||
_IPV6_PATTERN = r"^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
|
||||
_IPV6_RE = re.compile(_IPV6_PATTERN)
|
||||
##################################################################################################
|
||||
|
||||
|
@ -44,7 +45,7 @@ class ServerManual(xbmcgui.WindowXMLDialog):
|
|||
|
||||
def set_args(self, **kwargs):
|
||||
# connect_manager, user_image, servers, jellyfin_connect
|
||||
for key, value in kwargs.iteritems():
|
||||
for key, value in iteritems(kwargs):
|
||||
setattr(self, key, value)
|
||||
|
||||
def is_connected(self):
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from six import iteritems
|
||||
from kodi_six import xbmc, xbmcgui
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -34,7 +35,7 @@ class UsersConnect(xbmcgui.WindowXMLDialog):
|
|||
|
||||
def set_args(self, **kwargs):
|
||||
# connect_manager, user_image, servers
|
||||
for key, value in kwargs.iteritems():
|
||||
for key, value in iteritems(kwargs):
|
||||
setattr(self, key, value)
|
||||
|
||||
def is_user_selected(self):
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import Queue
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
from six.moves import queue as Queue
|
||||
|
||||
from kodi_six import xbmc
|
||||
import requests
|
||||
from helper import settings, stop, event, window, create_id
|
||||
from jellyfin import Jellyfin
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
|
||||
from helper import loghandler
|
||||
from jellyfin import Jellyfin
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,8 +7,7 @@ import json
|
|||
import logging
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
import database
|
||||
from dialogs import context
|
||||
|
@ -67,7 +67,7 @@ class Context(object):
|
|||
elif self.select_menu():
|
||||
self.action_menu()
|
||||
|
||||
if self._selected_option.decode('utf-8') in (OPTIONS['Delete'], OPTIONS['AddFav'], OPTIONS['RemoveFav']):
|
||||
if self._selected_option in (OPTIONS['Delete'], OPTIONS['AddFav'], OPTIONS['RemoveFav']):
|
||||
|
||||
xbmc.sleep(500)
|
||||
xbmc.executebuiltin('Container.Refresh')
|
||||
|
@ -91,7 +91,7 @@ class Context(object):
|
|||
else:
|
||||
LOG.info("media is unknown")
|
||||
|
||||
return media.decode('utf-8')
|
||||
return media
|
||||
|
||||
def get_item_id(self):
|
||||
|
||||
|
@ -140,7 +140,7 @@ class Context(object):
|
|||
|
||||
def action_menu(self):
|
||||
|
||||
selected = self._selected_option.decode('utf-8')
|
||||
selected = self._selected_option
|
||||
|
||||
if selected == OPTIONS['Refresh']:
|
||||
TheVoid('RefreshItem', {'ServerId': self.server, 'Id': self.item['Id']})
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import urlparse
|
||||
import urllib
|
||||
import os
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
from six.moves.urllib.parse import parse_qsl, urlencode
|
||||
from kodi_six import xbmc, xbmcvfs, xbmcgui, xbmcplugin, xbmcaddon
|
||||
|
||||
import client
|
||||
from database import reset, get_sync, Database, jellyfin_db, get_credentials
|
||||
|
@ -39,7 +35,7 @@ class Events(object):
|
|||
path = sys.argv[2]
|
||||
|
||||
try:
|
||||
params = dict(urlparse.parse_qsl(path[1:]))
|
||||
params = dict(parse_qsl(path[1:]))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
|
@ -146,7 +142,7 @@ def listing():
|
|||
context = []
|
||||
|
||||
if view_id and node in ('movies', 'tvshows', 'musicvideos', 'music', 'mixed') and view_id not in whitelist:
|
||||
label = "%s %s" % (label.decode('utf-8'), translate(33166))
|
||||
label = "%s %s" % (label, translate(33166))
|
||||
context.append((translate(33123), "RunPlugin(plugin://plugin.video.jellyfin/?mode=synclib&id=%s)" % view_id))
|
||||
|
||||
if view_id and node in ('movies', 'tvshows', 'musicvideos', 'music') and view_id in whitelist:
|
||||
|
@ -338,7 +334,7 @@ def browse(media, view_id=None, folder=None, server_id=None):
|
|||
'folder': item['Id'],
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
context = []
|
||||
|
||||
if item['Type'] in ('Series', 'Season', 'Playlist'):
|
||||
|
@ -361,7 +357,7 @@ def browse(media, view_id=None, folder=None, server_id=None):
|
|||
'folder': 'genres-%s' % item['Id'],
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
list_li.append((path, li, True))
|
||||
|
||||
else:
|
||||
|
@ -371,7 +367,7 @@ def browse(media, view_id=None, folder=None, server_id=None):
|
|||
'mode': "play",
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
li.setProperty('path', path)
|
||||
context = [(translate(13412), "RunPlugin(plugin://plugin.video.jellyfin/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))]
|
||||
|
||||
|
@ -415,7 +411,7 @@ def browse_subfolders(media, view_id, server_id=None):
|
|||
'folder': view_id if node[0] == 'all' else node[0],
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
directory(node[1] or view['Name'], path)
|
||||
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
|
@ -440,7 +436,7 @@ def browse_letters(media, view_id, server_id=None):
|
|||
'folder': 'firstletter-%s' % node,
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
directory(node, path)
|
||||
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
|
@ -497,7 +493,7 @@ def get_fanart(item_id, path, server_id=None):
|
|||
LOG.info("[ extra fanart ] %s", item_id)
|
||||
objects = Objects()
|
||||
list_li = []
|
||||
directory = xbmc.translatePath("special://thumbnails/jellyfin/%s/" % item_id).decode('utf-8')
|
||||
directory = xbmc.translatePath("special://thumbnails/jellyfin/%s/" % item_id)
|
||||
server = TheVoid('GetServerAddress', {'ServerId': server_id}).get()
|
||||
|
||||
if not xbmcvfs.exists(directory):
|
||||
|
@ -520,7 +516,7 @@ def get_fanart(item_id, path, server_id=None):
|
|||
dirs, files = xbmcvfs.listdir(directory)
|
||||
|
||||
for file in files:
|
||||
fanart = os.path.join(directory, file.decode('utf-8'))
|
||||
fanart = os.path.join(directory, file)
|
||||
li = xbmcgui.ListItem(file, path=fanart)
|
||||
list_li.append((fanart, li, False))
|
||||
|
||||
|
@ -773,7 +769,7 @@ def get_themes():
|
|||
from helper.playutils import PlayUtils
|
||||
from helper.xmls import tvtunes_nfo
|
||||
|
||||
library = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/library").decode('utf-8')
|
||||
library = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/library")
|
||||
play = settings('useDirectPaths') == "1"
|
||||
|
||||
if not xbmcvfs.exists(library + '/'):
|
||||
|
@ -803,14 +799,14 @@ def get_themes():
|
|||
|
||||
for item in result['Items']:
|
||||
|
||||
folder = normalize_string(item['Name'].encode('utf-8'))
|
||||
folder = normalize_string(item['Name'])
|
||||
items[item['Id']] = folder
|
||||
|
||||
result = TheVoid('GetThemes', {'Type': "Song", 'Id': view}).get()
|
||||
|
||||
for item in result['Items']:
|
||||
|
||||
folder = normalize_string(item['Name'].encode('utf-8'))
|
||||
folder = normalize_string(item['Name'])
|
||||
items[item['Id']] = folder
|
||||
|
||||
for item in items:
|
||||
|
@ -828,9 +824,9 @@ def get_themes():
|
|||
putils = PlayUtils(theme, False, None, server, token)
|
||||
|
||||
if play:
|
||||
paths.append(putils.direct_play(theme['MediaSources'][0]).encode('utf-8'))
|
||||
paths.append(putils.direct_play(theme['MediaSources'][0]))
|
||||
else:
|
||||
paths.append(putils.direct_url(theme['MediaSources'][0]).encode('utf-8'))
|
||||
paths.append(putils.direct_url(theme['MediaSources'][0]))
|
||||
|
||||
tvtunes_nfo(nfo_file, paths)
|
||||
|
||||
|
@ -868,7 +864,7 @@ def backup():
|
|||
|
||||
delete_folder(backup)
|
||||
|
||||
addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin").decode('utf-8')
|
||||
addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin")
|
||||
destination_data = os.path.join(backup, "addon_data", "plugin.video.jellyfin")
|
||||
destination_databases = os.path.join(backup, "Database")
|
||||
|
||||
|
@ -883,18 +879,18 @@ def backup():
|
|||
|
||||
databases = Objects().objects
|
||||
|
||||
db = xbmc.translatePath(databases['jellyfin']).decode('utf-8')
|
||||
db = xbmc.translatePath(databases['jellyfin'])
|
||||
xbmcvfs.copy(db, os.path.join(destination_databases, db.rsplit('\\', 1)[1]))
|
||||
LOG.info("copied jellyfin.db")
|
||||
|
||||
db = xbmc.translatePath(databases['video']).decode('utf-8')
|
||||
db = xbmc.translatePath(databases['video'])
|
||||
filename = db.rsplit('\\', 1)[1]
|
||||
xbmcvfs.copy(db, os.path.join(destination_databases, filename))
|
||||
LOG.info("copied %s", filename)
|
||||
|
||||
if settings('enableMusic.bool'):
|
||||
|
||||
db = xbmc.translatePath(databases['music']).decode('utf-8')
|
||||
db = xbmc.translatePath(databases['music'])
|
||||
filename = db.rsplit('\\', 1)[1]
|
||||
xbmcvfs.copy(db, os.path.join(destination_databases, filename))
|
||||
LOG.info("copied %s", filename)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -9,8 +10,8 @@ from datetime import datetime
|
|||
|
||||
# Workaround for threads using datetime: _striptime is locked
|
||||
import _strptime # noqa:F401
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from kodi_six import xbmc, xbmcgui
|
||||
from six.moves import reload_module as reload
|
||||
|
||||
import objects
|
||||
import connect
|
||||
|
@ -181,8 +182,8 @@ class Service(xbmc.Monitor):
|
|||
|
||||
if settings('connectMsg.bool'):
|
||||
|
||||
users = [user for user in (settings('additionalUsers') or "").decode('utf-8').split(',') if user]
|
||||
users.insert(0, settings('username').decode('utf-8'))
|
||||
users = [user for user in (settings('additionalUsers') or "").split(',') if user]
|
||||
users.insert(0, settings('username'))
|
||||
dialog("notification", heading="{jellyfin}", message="%s %s" % (translate(33000), ", ".join(users)),
|
||||
icon="{jellyfin}", time=1500, sound=False)
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
from kodi_six import xbmc
|
||||
|
||||
import downloader as server
|
||||
import helper.xmls as xmls
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
from translate import translate
|
||||
from exceptions import LibraryException
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from utils import addon_id
|
||||
from utils import window
|
||||
from utils import settings
|
||||
from utils import kodi_version
|
||||
from utils import dialog
|
||||
from utils import find
|
||||
from utils import event
|
||||
from utils import validate
|
||||
from utils import values
|
||||
from utils import JSONRPC
|
||||
from utils import indent
|
||||
from utils import write_xml
|
||||
from utils import compare_version
|
||||
from utils import unzip
|
||||
from utils import create_id
|
||||
from utils import convert_to_local as Local
|
||||
from utils import has_attribute
|
||||
from .translate import translate
|
||||
from .exceptions import LibraryException
|
||||
|
||||
from wrapper import progress
|
||||
from wrapper import catch
|
||||
from wrapper import silent_catch
|
||||
from wrapper import stop
|
||||
from wrapper import jellyfin_item
|
||||
from wrapper import library_check
|
||||
from .utils import addon_id
|
||||
from .utils import window
|
||||
from .utils import settings
|
||||
from .utils import kodi_version
|
||||
from .utils import dialog
|
||||
from .utils import find
|
||||
from .utils import event
|
||||
from .utils import validate
|
||||
from .utils import values
|
||||
from .utils import JSONRPC
|
||||
from .utils import indent
|
||||
from .utils import write_xml
|
||||
from .utils import compare_version
|
||||
from .utils import unzip
|
||||
from .utils import create_id
|
||||
from .utils import convert_to_local as Local
|
||||
from .utils import has_attribute
|
||||
|
||||
from .wrapper import progress
|
||||
from .wrapper import catch
|
||||
from .wrapper import silent_catch
|
||||
from .wrapper import stop
|
||||
from .wrapper import jellyfin_item
|
||||
from .wrapper import library_check
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
@ -9,8 +10,7 @@ import os
|
|||
import logging
|
||||
import traceback
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
import database
|
||||
|
||||
from . import window, settings
|
||||
|
@ -18,7 +18,7 @@ from . import window, settings
|
|||
##################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin')
|
||||
__pluginpath__ = xbmc.translatePath(__addon__.getAddonInfo('path').decode('utf-8'))
|
||||
__pluginpath__ = xbmc.translatePath(__addon__.getAddonInfo('path'))
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -65,15 +65,15 @@ class LogHandler(logging.StreamHandler):
|
|||
|
||||
if self.mask_info:
|
||||
for server in self.sensitive['Server']:
|
||||
string = string.replace(server.encode('utf-8') or "{server}", "{jellyfin-server}")
|
||||
string = string.replace(server or "{server}", "{jellyfin-server}")
|
||||
|
||||
for token in self.sensitive['Token']:
|
||||
string = string.replace(token.encode('utf-8') or "{token}", "{jellyfin-token}")
|
||||
string = string.replace(token or "{token}", "{jellyfin-token}")
|
||||
|
||||
try:
|
||||
xbmc.log(string, level=xbmc.LOGNOTICE)
|
||||
except UnicodeEncodeError:
|
||||
xbmc.log(string.encode('utf-8'), level=xbmc.LOGNOTICE)
|
||||
xbmc.log(string, level=xbmc.LOGNOTICE)
|
||||
|
||||
@classmethod
|
||||
def _get_log_level(cls, level):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -7,15 +8,13 @@ import os
|
|||
from uuid import uuid4
|
||||
import collections
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
|
||||
import api
|
||||
import client
|
||||
import requests
|
||||
from downloader import TheVoid
|
||||
|
||||
from . import translate, settings, window, dialog
|
||||
from . import translate, settings, window, dialog, api
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -212,7 +211,7 @@ class PlayUtils(object):
|
|||
self.item['PlaybackInfo'].update(self.info)
|
||||
|
||||
API = api.API(self.item, self.info['ServerAddress'])
|
||||
window('jellyfinfilename', value=API.get_file_path(source.get('Path')).encode('utf-8'))
|
||||
window('jellyfinfilename', value=API.get_file_path(source.get('Path')))
|
||||
|
||||
def live_stream(self, source):
|
||||
|
||||
|
@ -484,7 +483,7 @@ class PlayUtils(object):
|
|||
LOG.info("[ subtitles/%s ] %s", index, url)
|
||||
|
||||
if 'Language' in stream:
|
||||
filename = "Stream.%s.%s" % (stream['Language'].encode('utf-8'), stream['Codec'].encode('utf-8'))
|
||||
filename = "Stream.%s.%s" % (stream['Language'], stream['Codec'])
|
||||
|
||||
try:
|
||||
subs.append(self.download_external_subs(url, filename))
|
||||
|
@ -506,7 +505,7 @@ class PlayUtils(object):
|
|||
''' Download external subtitles to temp folder
|
||||
to be able to have proper names to streams.
|
||||
'''
|
||||
temp = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/").decode('utf-8')
|
||||
temp = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/")
|
||||
|
||||
if not xbmcvfs.exists(temp):
|
||||
xbmcvfs.mkdir(temp)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -8,18 +9,16 @@ import logging
|
|||
import os
|
||||
import re
|
||||
import unicodedata
|
||||
import urllib
|
||||
from uuid import uuid4
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
from dateutil import tz, parser
|
||||
from six import text_type, string_types, iteritems
|
||||
from six.moves.urllib.parse import quote_plus
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcaddon, xbmcgui, xbmcvfs
|
||||
|
||||
from translate import translate
|
||||
from .translate import translate
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -122,7 +121,7 @@ def find(dict, item):
|
|||
if item in dict:
|
||||
return dict[item]
|
||||
|
||||
for key, value in sorted(dict.iteritems(), key=lambda (k, v): (v, k)):
|
||||
for key, value in sorted(iteritems(dict), key=lambda kv: (kv[1], kv[0])):
|
||||
|
||||
if re.match(key, item, re.I):
|
||||
return dict[key]
|
||||
|
@ -245,7 +244,7 @@ def validate(path):
|
|||
if window('jellyfin_pathverified.bool'):
|
||||
return True
|
||||
|
||||
path = path if os.path.supports_unicode_filenames else path.encode('utf-8')
|
||||
path = path if os.path.supports_unicode_filenames else path
|
||||
|
||||
if not xbmcvfs.exists(path):
|
||||
LOG.info("Could not find %s", path)
|
||||
|
@ -291,14 +290,17 @@ def indent(elem, level=0):
|
|||
|
||||
|
||||
def write_xml(content, file):
|
||||
with open(file, 'w') as infile:
|
||||
if isinstance(content, text_type):
|
||||
content = content.encode('utf-8')
|
||||
|
||||
with open(file, 'wb') as infile:
|
||||
|
||||
# replace apostrophes with double quotes only in xml keys, not texts
|
||||
def replace_apostrophes(match):
|
||||
return match.group(0).replace("'", '"')
|
||||
content = re.sub("<(.*?)>", replace_apostrophes, content)
|
||||
return match.group(0).replace(b"'", b'"')
|
||||
content = re.sub(b"<(.*?)>", replace_apostrophes, content)
|
||||
|
||||
content = content.replace('?>', ' standalone="yes" ?>', 1)
|
||||
content = content.replace(b'?>', b' standalone="yes" ?>', 1)
|
||||
infile.write(content)
|
||||
|
||||
|
||||
|
@ -312,7 +314,7 @@ def delete_folder(path):
|
|||
delete_recursive(path, dirs)
|
||||
|
||||
for file in files:
|
||||
xbmcvfs.delete(os.path.join(path, file.decode('utf-8')))
|
||||
xbmcvfs.delete(os.path.join(path, file))
|
||||
|
||||
xbmcvfs.delete(path)
|
||||
|
||||
|
@ -324,20 +326,20 @@ def delete_recursive(path, dirs):
|
|||
''' Delete files and dirs recursively.
|
||||
'''
|
||||
for directory in dirs:
|
||||
dirs2, files = xbmcvfs.listdir(os.path.join(path, directory.decode('utf-8')))
|
||||
dirs2, files = xbmcvfs.listdir(os.path.join(path, directory))
|
||||
|
||||
for file in files:
|
||||
xbmcvfs.delete(os.path.join(path, directory.decode('utf-8'), file.decode('utf-8')))
|
||||
xbmcvfs.delete(os.path.join(path, directory, file))
|
||||
|
||||
delete_recursive(os.path.join(path, directory.decode('utf-8')), dirs2)
|
||||
xbmcvfs.rmdir(os.path.join(path, directory.decode('utf-8')))
|
||||
delete_recursive(os.path.join(path, directory), dirs2)
|
||||
xbmcvfs.rmdir(os.path.join(path, directory))
|
||||
|
||||
|
||||
def unzip(path, dest, folder=None):
|
||||
|
||||
''' Unzip file. zipfile module seems to fail on android with badziperror.
|
||||
'''
|
||||
path = urllib.quote_plus(path)
|
||||
path = quote_plus(path)
|
||||
root = "zip://" + path + '/'
|
||||
|
||||
if folder:
|
||||
|
@ -352,7 +354,7 @@ def unzip(path, dest, folder=None):
|
|||
unzip_recursive(root, dirs, dest)
|
||||
|
||||
for file in files:
|
||||
unzip_file(os.path.join(root, file.decode('utf-8')), os.path.join(dest, file.decode('utf-8')))
|
||||
unzip_file(os.path.join(root, file), os.path.join(dest, file))
|
||||
|
||||
LOG.info("Unzipped %s", path)
|
||||
|
||||
|
@ -361,8 +363,8 @@ def unzip_recursive(path, dirs, dest):
|
|||
|
||||
for directory in dirs:
|
||||
|
||||
dirs_dir = os.path.join(path, directory.decode('utf-8'))
|
||||
dest_dir = os.path.join(dest, directory.decode('utf-8'))
|
||||
dirs_dir = os.path.join(path, directory)
|
||||
dest_dir = os.path.join(dest, directory)
|
||||
xbmcvfs.mkdir(dest_dir)
|
||||
|
||||
dirs2, files = xbmcvfs.listdir(dirs_dir)
|
||||
|
@ -371,7 +373,7 @@ def unzip_recursive(path, dirs, dest):
|
|||
unzip_recursive(dirs_dir, dirs2, dest_dir)
|
||||
|
||||
for file in files:
|
||||
unzip_file(os.path.join(dirs_dir, file.decode('utf-8')), os.path.join(dest_dir, file.decode('utf-8')))
|
||||
unzip_file(os.path.join(dirs_dir, file), os.path.join(dest_dir, file))
|
||||
|
||||
|
||||
def unzip_file(path, dest):
|
||||
|
@ -390,7 +392,7 @@ def get_zip_directory(path, folder):
|
|||
return os.path.join(path, folder)
|
||||
|
||||
for directory in dirs:
|
||||
result = get_zip_directory(os.path.join(path, directory.decode('utf-8')), folder)
|
||||
result = get_zip_directory(os.path.join(path, directory), folder)
|
||||
if result:
|
||||
return result
|
||||
|
||||
|
@ -408,7 +410,7 @@ def copytree(path, dest):
|
|||
copy_recursive(path, dirs, dest)
|
||||
|
||||
for file in files:
|
||||
copy_file(os.path.join(path, file.decode('utf-8')), os.path.join(dest, file.decode('utf-8')))
|
||||
copy_file(os.path.join(path, file), os.path.join(dest, file))
|
||||
|
||||
LOG.info("Copied %s", path)
|
||||
|
||||
|
@ -417,8 +419,8 @@ def copy_recursive(path, dirs, dest):
|
|||
|
||||
for directory in dirs:
|
||||
|
||||
dirs_dir = os.path.join(path, directory.decode('utf-8'))
|
||||
dest_dir = os.path.join(dest, directory.decode('utf-8'))
|
||||
dirs_dir = os.path.join(path, directory)
|
||||
dest_dir = os.path.join(dest, directory)
|
||||
xbmcvfs.mkdir(dest_dir)
|
||||
|
||||
dirs2, files = xbmcvfs.listdir(dirs_dir)
|
||||
|
@ -427,7 +429,7 @@ def copy_recursive(path, dirs, dest):
|
|||
copy_recursive(dirs_dir, dirs2, dest_dir)
|
||||
|
||||
for file in files:
|
||||
copy_file(os.path.join(dirs_dir, file.decode('utf-8')), os.path.join(dest_dir, file.decode('utf-8')))
|
||||
copy_file(os.path.join(dirs_dir, file), os.path.join(dest_dir, file))
|
||||
|
||||
|
||||
def copy_file(path, dest):
|
||||
|
@ -458,7 +460,7 @@ def normalize_string(text):
|
|||
text = text.strip()
|
||||
|
||||
text = text.rstrip('.')
|
||||
text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
|
||||
text = unicodedata.normalize('NFKD', text_type(text, 'utf-8')).encode('ascii', 'ignore')
|
||||
|
||||
return text
|
||||
|
||||
|
@ -475,7 +477,7 @@ def convert_to_local(date):
|
|||
''' Convert the local datetime to local.
|
||||
'''
|
||||
try:
|
||||
date = parser.parse(date) if type(date) in (unicode, str) else date
|
||||
date = parser.parse(date) if isinstance(date, string_types) else date
|
||||
date = date.replace(tzinfo=tz.tzutc())
|
||||
date = date.astimezone(tz.tzlocal())
|
||||
|
||||
|
@ -485,6 +487,7 @@ def convert_to_local(date):
|
|||
|
||||
return str(date)
|
||||
|
||||
|
||||
def has_attribute(obj, name):
|
||||
try:
|
||||
object.__getattribute__(obj, name)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import xbmcgui
|
||||
from kodi_six import xbmcgui
|
||||
|
||||
from .utils import should_stop
|
||||
from .exceptions import LibraryException
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,7 +7,7 @@ import logging
|
|||
import os
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
import xbmc
|
||||
from kodi_six import xbmc
|
||||
|
||||
from . import translate, indent, write_xml, dialog, settings
|
||||
|
||||
|
@ -22,7 +23,7 @@ def sources():
|
|||
''' Create master lock compatible sources.
|
||||
Also add the kodi.jellyfin.media source.
|
||||
'''
|
||||
path = xbmc.translatePath("special://profile/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/")
|
||||
file = os.path.join(path, 'sources.xml')
|
||||
|
||||
try:
|
||||
|
@ -106,7 +107,7 @@ def advanced_settings():
|
|||
if settings('useDirectPaths') != "0":
|
||||
return
|
||||
|
||||
path = xbmc.translatePath("special://profile/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/")
|
||||
file = os.path.join(path, 'advancedsettings.xml')
|
||||
|
||||
try:
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
from client import JellyfinClient
|
||||
from .client import JellyfinClient
|
||||
from helper import has_attribute
|
||||
|
||||
#################################################################################################
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
|
||||
def jellyfin_url(client, handler):
|
||||
return "%s/%s" % (client.config.data['auth.server'], handler)
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import api
|
||||
from configuration import Config
|
||||
from http import HTTP
|
||||
from ws_client import WSClient
|
||||
from connection_manager import ConnectionManager, CONNECTION_STATE
|
||||
from . import api
|
||||
from .configuration import Config
|
||||
from .http import HTTP
|
||||
from .ws_client import WSClient
|
||||
from .connection_manager import ConnectionManager, CONNECTION_STATE
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
''' This will hold all configs from the client.
|
||||
Configuration set here will be used for the HTTP client.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -11,8 +12,8 @@ from distutils.version import LooseVersion
|
|||
|
||||
import urllib3
|
||||
|
||||
from credentials import Credentials
|
||||
from http import HTTP # noqa: I201,I100
|
||||
from .credentials import Credentials
|
||||
from .http import HTTP # noqa: I201,I100
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -258,7 +259,7 @@ class ConnectionManager(object):
|
|||
def _server_discovery(self):
|
||||
|
||||
MULTI_GROUP = ("<broadcast>", 7359)
|
||||
MESSAGE = "who is JellyfinServer?"
|
||||
MESSAGE = b"who is JellyfinServer?"
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.settimeout(1.0) # This controls the socket.timeout exception
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -7,7 +8,8 @@ import logging
|
|||
import time
|
||||
|
||||
import requests
|
||||
from exceptions import HTTPException
|
||||
|
||||
from .exceptions import HTTPException
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -49,13 +51,13 @@ class HTTP(object):
|
|||
|
||||
if '{server}' in string:
|
||||
if self.config.data['auth.server']:
|
||||
string = string.decode('utf-8').replace("{server}", self.config.data['auth.server'])
|
||||
string = string.replace("{server}", self.config.data['auth.server'])
|
||||
else:
|
||||
raise Exception("Server address not set.")
|
||||
|
||||
if '{UserId}'in string:
|
||||
if self.config.data['auth.user_id']:
|
||||
string = string.decode('utf-8').replace("{UserId}", self.config.data['auth.user_id'])
|
||||
string = string.replace("{UserId}", self.config.data['auth.user_id'])
|
||||
else:
|
||||
raise Exception("UserId is not set.")
|
||||
|
||||
|
@ -209,17 +211,17 @@ class HTTP(object):
|
|||
def _authorization(self, data):
|
||||
|
||||
auth = "MediaBrowser "
|
||||
auth += "Client=%s, " % self.config.data['app.name'].encode('utf-8')
|
||||
auth += "Device=%s, " % self.config.data['app.device_name'].encode('utf-8')
|
||||
auth += "DeviceId=%s, " % self.config.data['app.device_id'].encode('utf-8')
|
||||
auth += "Version=%s" % self.config.data['app.version'].encode('utf-8')
|
||||
auth += "Client=%s, " % self.config.data['app.name']
|
||||
auth += "Device=%s, " % self.config.data['app.device_name']
|
||||
auth += "DeviceId=%s, " % self.config.data['app.device_id']
|
||||
auth += "Version=%s" % self.config.data['app.version']
|
||||
|
||||
data['headers'].update({'x-emby-authorization': auth})
|
||||
|
||||
if self.config.data.get('auth.token') and self.config.data.get('auth.user_id'):
|
||||
|
||||
auth += ', UserId=%s' % self.config.data['auth.user_id'].encode('utf-8')
|
||||
data['headers'].update({'x-emby-authorization': auth, 'X-MediaBrowser-Token': self.config.data['auth.token'].encode('utf-8')})
|
||||
auth += ', UserId=%s' % self.config.data['auth.user_id']
|
||||
data['headers'].update({'x-emby-authorization': auth, 'X-MediaBrowser-Token': self.config.data['auth.token']})
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
"""
|
||||
websocket - WebSocket client library for Python
|
||||
|
||||
|
@ -33,7 +34,7 @@ except ImportError:
|
|||
|
||||
HAVE_SSL = False
|
||||
|
||||
from urlparse import urlparse
|
||||
|
||||
import os
|
||||
import array
|
||||
import struct
|
||||
|
@ -44,6 +45,10 @@ import threading
|
|||
import time
|
||||
import logging
|
||||
|
||||
from six import text_type, string_types, iteritems, int2byte, indexbytes
|
||||
from six.moves import range
|
||||
from six.moves.urllib.parse import urlparse
|
||||
|
||||
"""
|
||||
websocket python client.
|
||||
=========================
|
||||
|
@ -221,7 +226,7 @@ def create_connection(url, timeout=None, **options):
|
|||
|
||||
|
||||
_MAX_INTEGER = (1 << 32) - 1
|
||||
_AVAILABLE_KEY_CHARS = range(0x21, 0x2f + 1) + range(0x3a, 0x7e + 1)
|
||||
_AVAILABLE_KEY_CHARS = list(range(0x21, 0x2f + 1)) + list(range(0x3a, 0x7e + 1))
|
||||
_MAX_CHAR_BYTE = (1 << 8) - 1
|
||||
|
||||
# ref. Websocket gets an update, and it breaks stuff.
|
||||
|
@ -304,7 +309,7 @@ class ABNF(object):
|
|||
|
||||
opcode: operation code. please see OPCODE_XXX.
|
||||
"""
|
||||
if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode):
|
||||
if opcode == ABNF.OPCODE_TEXT and isinstance(data, text_type):
|
||||
data = data.encode("utf-8")
|
||||
# mask must be set if send data from client
|
||||
return ABNF(1, 0, 0, 0, opcode, 1, data)
|
||||
|
@ -321,14 +326,14 @@ class ABNF(object):
|
|||
if length >= ABNF.LENGTH_63:
|
||||
raise ValueError("data is too long")
|
||||
|
||||
frame_header = chr(self.fin << 7 | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 | self.opcode)
|
||||
frame_header = int2byte(self.fin << 7 | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 | self.opcode)
|
||||
if length < ABNF.LENGTH_7:
|
||||
frame_header += chr(self.mask << 7 | length)
|
||||
frame_header += int2byte(self.mask << 7 | length)
|
||||
elif length < ABNF.LENGTH_16:
|
||||
frame_header += chr(self.mask << 7 | 0x7e)
|
||||
frame_header += int2byte(self.mask << 7 | 0x7e)
|
||||
frame_header += struct.pack("!H", length)
|
||||
else:
|
||||
frame_header += chr(self.mask << 7 | 0x7f)
|
||||
frame_header += int2byte(self.mask << 7 | 0x7f)
|
||||
frame_header += struct.pack("!Q", length)
|
||||
|
||||
if not self.mask:
|
||||
|
@ -352,7 +357,7 @@ class ABNF(object):
|
|||
"""
|
||||
_m = array.array("B", mask_key)
|
||||
_d = array.array("B", data)
|
||||
for i in xrange(len(_d)):
|
||||
for i in range(len(_d)):
|
||||
_d[i] ^= _m[i % 4]
|
||||
return _d.tostring()
|
||||
|
||||
|
@ -475,31 +480,39 @@ class WebSocket(object):
|
|||
self._handshake(hostname, port, resource, **options)
|
||||
|
||||
def _handshake(self, host, port, resource, **options):
|
||||
if isinstance(host, string_types):
|
||||
host = host.encode('utf-8')
|
||||
if isinstance(resource, string_types):
|
||||
resource = resource.encode('utf-8')
|
||||
|
||||
headers = []
|
||||
headers.append("GET %s HTTP/1.1" % resource)
|
||||
headers.append("Upgrade: websocket")
|
||||
headers.append("Connection: Upgrade")
|
||||
headers.append(b"GET %s HTTP/1.1" % resource)
|
||||
headers.append(b"Upgrade: websocket")
|
||||
headers.append(b"Connection: Upgrade")
|
||||
if port == 80:
|
||||
hostport = host
|
||||
else:
|
||||
hostport = "%s:%d" % (host, port)
|
||||
headers.append("Host: %s" % hostport)
|
||||
hostport = b"%s:%d" % (host, port)
|
||||
headers.append(b"Host: %s" % hostport)
|
||||
|
||||
if "origin" in options:
|
||||
headers.append("Origin: %s" % options["origin"])
|
||||
headers.append(b"Origin: %s" % options["origin"])
|
||||
else:
|
||||
headers.append("Origin: http://%s" % hostport)
|
||||
headers.append(b"Origin: http://%s" % hostport)
|
||||
|
||||
key = _create_sec_websocket_key()
|
||||
headers.append("Sec-WebSocket-Key: %s" % key)
|
||||
headers.append("Sec-WebSocket-Version: %s" % VERSION)
|
||||
headers.append(b"Sec-WebSocket-Key: %s" % key)
|
||||
headers.append(b"Sec-WebSocket-Version: %d" % VERSION)
|
||||
if "header" in options:
|
||||
headers.extend(options["header"])
|
||||
for header in options["header"]:
|
||||
if isinstance(header, string_types):
|
||||
header = header.encode('utf-8')
|
||||
headers.extend(header)
|
||||
|
||||
headers.append("")
|
||||
headers.append("")
|
||||
headers.append(b"")
|
||||
headers.append(b"")
|
||||
|
||||
header_str = "\r\n".join(headers)
|
||||
header_str = b"\r\n".join(headers)
|
||||
self._send(header_str)
|
||||
if traceEnabled:
|
||||
logger.debug("--- request header ---")
|
||||
|
@ -519,7 +532,7 @@ class WebSocket(object):
|
|||
self.connected = True
|
||||
|
||||
def _validate_header(self, headers, key):
|
||||
for k, v in _HEADERS_TO_CHECK.iteritems():
|
||||
for k, v in iteritems(_HEADERS_TO_CHECK):
|
||||
r = headers.get(k, None)
|
||||
if not r:
|
||||
return False
|
||||
|
@ -653,13 +666,13 @@ class WebSocket(object):
|
|||
# Header
|
||||
if self._frame_header is None:
|
||||
self._frame_header = self._recv_strict(2)
|
||||
b1 = ord(self._frame_header[0])
|
||||
b1 = indexbytes(self._frame_header, 0)
|
||||
fin = b1 >> 7 & 1
|
||||
rsv1 = b1 >> 6 & 1
|
||||
rsv2 = b1 >> 5 & 1
|
||||
rsv3 = b1 >> 4 & 1
|
||||
opcode = b1 & 0xf
|
||||
b2 = ord(self._frame_header[1])
|
||||
b2 = indexbytes(self._frame_header, 1)
|
||||
has_mask = b2 >> 7 & 1
|
||||
# Frame length
|
||||
if self._frame_length is None:
|
||||
|
@ -753,7 +766,7 @@ class WebSocket(object):
|
|||
|
||||
def _recv(self, bufsize):
|
||||
try:
|
||||
bytes = self.sock.recv(bufsize)
|
||||
_bytes = self.sock.recv(bufsize)
|
||||
except socket.timeout as e:
|
||||
raise WebSocketTimeoutException(e.args[0])
|
||||
except SSLError as e:
|
||||
|
@ -761,16 +774,16 @@ class WebSocket(object):
|
|||
raise WebSocketTimeoutException(e.args[0])
|
||||
else:
|
||||
raise
|
||||
if not bytes:
|
||||
if not _bytes:
|
||||
raise WebSocketConnectionClosedException()
|
||||
return bytes
|
||||
return _bytes
|
||||
|
||||
def _recv_strict(self, bufsize):
|
||||
shortage = bufsize - sum(len(x) for x in self._recv_buffer)
|
||||
while shortage > 0:
|
||||
bytes = self._recv(shortage)
|
||||
self._recv_buffer.append(bytes)
|
||||
shortage -= len(bytes)
|
||||
_bytes = self._recv(shortage)
|
||||
self._recv_buffer.append(_bytes)
|
||||
shortage -= len(_bytes)
|
||||
unified = "".join(self._recv_buffer)
|
||||
if shortage == 0:
|
||||
self._recv_buffer = []
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -6,9 +7,9 @@ import json
|
|||
import logging
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
from kodi_six import xbmc
|
||||
|
||||
import websocket
|
||||
from . import websocket
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
import Queue
|
||||
import threading
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
from six.moves import queue as Queue
|
||||
|
||||
from kodi_six import xbmc, xbmcgui
|
||||
|
||||
from objects import Movies, TVShows, MusicVideos, Music
|
||||
from database import Database, jellyfin_db, get_sync, save_sync
|
||||
|
@ -495,7 +496,7 @@ class Library(threading.Thread):
|
|||
"AddLibrarySelection": 33120
|
||||
}
|
||||
title = titles.get(mode, "Failed to get title {}".format(mode))
|
||||
|
||||
|
||||
selection = dialog("multi", translate(title), choices)
|
||||
|
||||
if selection is None:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -7,7 +8,7 @@ import json
|
|||
import logging
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
from kodi_six import xbmc
|
||||
|
||||
import connect
|
||||
import downloader
|
||||
|
@ -144,7 +145,7 @@ class Monitor(xbmc.Monitor):
|
|||
self.void_responder(data, item)
|
||||
|
||||
elif method == 'GetServerAddress':
|
||||
|
||||
|
||||
server_address = server.auth.get_server_info(server.auth.server_id)['address']
|
||||
self.void_responder(data, server_address)
|
||||
|
||||
|
@ -291,7 +292,7 @@ class Monitor(xbmc.Monitor):
|
|||
for additional in users:
|
||||
for user in all_users:
|
||||
|
||||
if user['Name'].lower() in additional.decode('utf-8').lower():
|
||||
if user['Name'].lower() in additional.lower():
|
||||
server.jellyfin.session_add_user(server.config.data['app.session'], user['Id'], True)
|
||||
|
||||
self.additional_users(server)
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
from movies import Movies
|
||||
from musicvideos import MusicVideos
|
||||
from tvshows import TVShows
|
||||
from music import Music
|
||||
from obj import Objects
|
||||
from actions import Actions
|
||||
from actions import PlaylistWorker
|
||||
from actions import on_play, on_update, special_listener
|
||||
import utils
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from .movies import Movies
|
||||
from .musicvideos import MusicVideos
|
||||
from .tvshows import TVShows
|
||||
from .music import Music
|
||||
from .obj import Objects
|
||||
from .actions import Actions
|
||||
from .actions import PlaylistWorker
|
||||
from .actions import on_play, on_update, special_listener
|
||||
from . import utils
|
||||
|
||||
Objects().mapping()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -7,14 +8,11 @@ import threading
|
|||
import sys
|
||||
from datetime import timedelta
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcgui, xbmcplugin, xbmcaddon
|
||||
|
||||
import database
|
||||
from downloader import TheVoid
|
||||
from obj import Objects
|
||||
from .obj import Objects
|
||||
from helper import translate, playutils, api, window, settings, dialog
|
||||
from dialogs import resume
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from kodi import Kodi
|
||||
from movies import Movies
|
||||
from musicvideos import MusicVideos
|
||||
from tvshows import TVShows
|
||||
from music import Music
|
||||
from artwork import Artwork
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
from .kodi import Kodi
|
||||
from .movies import Movies
|
||||
from .musicvideos import MusicVideos
|
||||
from .tvshows import TVShows
|
||||
from .music import Music
|
||||
from .artwork import Artwork
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
import Queue
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from six.moves import queue as Queue
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
import queries as QU
|
||||
import queries_texture as QUTEX
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
|
||||
from . import queries as QU
|
||||
from . import queries_texture as QUTEX
|
||||
from helper import settings
|
||||
import requests
|
||||
|
||||
|
@ -139,10 +140,10 @@ class Artwork(object):
|
|||
''' urlencode needs a utf-string.
|
||||
return the result as unicode
|
||||
'''
|
||||
text = urllib.urlencode({'blahblahblah': text.encode('utf-8')})
|
||||
text = urlencode({'blahblahblah': text})
|
||||
text = text[13:]
|
||||
|
||||
return text.decode('utf-8')
|
||||
return text
|
||||
|
||||
def add_worker(self):
|
||||
|
||||
|
@ -170,7 +171,7 @@ class Artwork(object):
|
|||
except TypeError:
|
||||
LOG.debug("Could not find cached url: %s", url)
|
||||
else:
|
||||
thumbnails = xbmc.translatePath("special://thumbnails/%s" % cached).decode('utf-8')
|
||||
thumbnails = xbmc.translatePath("special://thumbnails/%s" % cached)
|
||||
xbmcvfs.delete(thumbnails)
|
||||
texturedb.cursor.execute(QUTEX.delete_cache, (url,))
|
||||
LOG.info("DELETE cached %s", cached)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import artwork
|
||||
import queries as QU
|
||||
from . import artwork
|
||||
from . import queries as QU
|
||||
from helper import values
|
||||
|
||||
##################################################################################################
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
from kodi import Kodi
|
||||
import queries as QU
|
||||
from .kodi import Kodi
|
||||
from . import queries as QU
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import queries_music as QU
|
||||
from kodi import Kodi
|
||||
from . import queries_music as QU
|
||||
from .kodi import Kodi
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import queries as QU
|
||||
from kodi import Kodi
|
||||
from . import queries as QU
|
||||
from .kodi import Kodi
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
''' Queries for the Kodi database. obj reflect key/value to retrieve from jellyfin items.
|
||||
Some functions require additional information, therefore obj do not always reflect
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
create_artist = """
|
||||
SELECT coalesce(max(idArtist), 1)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
get_cache = """
|
||||
SELECT cachedurl
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
|
||||
import queries as QU
|
||||
from kodi import Kodi
|
||||
from . import queries as QU
|
||||
from .kodi import Kodi
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
import downloader as server
|
||||
from obj import Objects
|
||||
from kodi import Movies as KodiDb, queries as QU
|
||||
from .obj import Objects
|
||||
from .kodi import Movies as KodiDb, queries as QU
|
||||
from database import jellyfin_db, queries as QUEM
|
||||
from helper import api, stop, validate, jellyfin_item, library_check, values, settings, Local
|
||||
|
||||
|
@ -177,12 +178,12 @@ class Movies(KodiDb):
|
|||
else:
|
||||
obj['Path'] = "plugin://plugin.video.jellyfin/%s/" % obj['LibraryId']
|
||||
params = {
|
||||
'filename': obj['Filename'].encode('utf-8'),
|
||||
'filename': obj['Filename'],
|
||||
'id': obj['Id'],
|
||||
'dbid': obj['MovieId'],
|
||||
'mode': "play"
|
||||
}
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urlencode(params))
|
||||
|
||||
@stop()
|
||||
@jellyfin_item()
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from obj import Objects
|
||||
from kodi import Music as KodiDb, queries_music as QU
|
||||
from .obj import Objects
|
||||
from .kodi import Music as KodiDb, queries_music as QU
|
||||
from database import jellyfin_db, queries as QUEM
|
||||
from helper import api, stop, validate, jellyfin_item, values, library_check, Local
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import re
|
||||
import urllib
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from obj import Objects
|
||||
from kodi import MusicVideos as KodiDb, queries as QU
|
||||
from .obj import Objects
|
||||
from .kodi import MusicVideos as KodiDb, queries as QU
|
||||
from database import jellyfin_db, queries as QUEM
|
||||
from helper import api, stop, validate, library_check, jellyfin_item, values, Local
|
||||
|
||||
|
@ -165,12 +166,12 @@ class MusicVideos(KodiDb):
|
|||
else:
|
||||
obj['Path'] = "plugin://plugin.video.jellyfin/%s/" % obj['LibraryId']
|
||||
params = {
|
||||
'filename': obj['Filename'].encode('utf-8'),
|
||||
'filename': obj['Filename'],
|
||||
'id': obj['Id'],
|
||||
'dbid': obj['MvideoId'],
|
||||
'mode': "play"
|
||||
}
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urlencode(params))
|
||||
|
||||
@stop()
|
||||
@jellyfin_item()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -6,6 +7,8 @@ import json
|
|||
import logging
|
||||
import os
|
||||
|
||||
from six import iteritems
|
||||
|
||||
##################################################################################################
|
||||
|
||||
LOG = logging.getLogger("JELLYFIN." + __name__)
|
||||
|
@ -53,7 +56,7 @@ class Objects(object):
|
|||
|
||||
mapping = self.objects[mapping_name]
|
||||
|
||||
for key, value in mapping.iteritems():
|
||||
for key, value in iteritems(mapping):
|
||||
|
||||
self.mapped_item[key] = None
|
||||
params = value.split(',')
|
||||
|
@ -144,7 +147,7 @@ class Objects(object):
|
|||
|
||||
result = False
|
||||
|
||||
for key, value in filters.iteritems():
|
||||
for key, value in iteritems(filters):
|
||||
|
||||
inverse = False
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
import urllib
|
||||
from ntpath import dirname
|
||||
|
||||
from obj import Objects
|
||||
from kodi import TVShows as KodiDb, queries as QU
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
from .obj import Objects
|
||||
from .kodi import TVShows as KodiDb, queries as QU
|
||||
import downloader as server
|
||||
from database import jellyfin_db, queries as QUEM
|
||||
from helper import api, stop, validate, jellyfin_item, library_check, settings, values, Local
|
||||
|
@ -392,12 +394,12 @@ class TVShows(KodiDb):
|
|||
else:
|
||||
obj['Path'] = "plugin://plugin.video.jellyfin/%s/" % obj['SeriesId']
|
||||
params = {
|
||||
'filename': obj['Filename'].encode('utf-8'),
|
||||
'filename': obj['Filename'],
|
||||
'id': obj['Id'],
|
||||
'dbid': obj['EpisodeId'],
|
||||
'mode': "play"
|
||||
}
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))
|
||||
obj['Filename'] = "%s?%s" % (obj['Path'], urlencode(params))
|
||||
|
||||
def get_show_id(self, obj):
|
||||
obj['ShowId'] = self.jellyfin_db.get_item_by_id(*values(obj, QUEM.get_item_series_obj))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
|
||||
from objects.obj import Objects
|
||||
from helper import translate, api, window, settings, dialog, event, silent_catch, JSONRPC
|
||||
|
@ -85,7 +85,7 @@ class Player(xbmc.Player):
|
|||
return
|
||||
|
||||
for item in items:
|
||||
if item['Path'] == current_file.decode('utf-8'):
|
||||
if item['Path'] == current_file:
|
||||
items.pop(items.index(item))
|
||||
|
||||
break
|
||||
|
@ -412,13 +412,13 @@ class Player(xbmc.Player):
|
|||
LOG.info("<[ transcode/%s ]", item['Id'])
|
||||
item['Server'].jellyfin.close_transcode(item['DeviceId'])
|
||||
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/")
|
||||
|
||||
if xbmcvfs.exists(path):
|
||||
dirs, files = xbmcvfs.listdir(path)
|
||||
|
||||
for file in files:
|
||||
xbmcvfs.delete(os.path.join(path, file.decode('utf-8')))
|
||||
xbmcvfs.delete(os.path.join(path, file))
|
||||
|
||||
result = item['Server'].jellyfin.get_item(item['Id']) or {}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import urllib
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from kodi_six import xbmc, xbmcvfs
|
||||
|
||||
from database import Database, jellyfin_db, get_sync, save_sync
|
||||
from helper import translate, api, indent, write_xml, window, event
|
||||
|
@ -108,13 +108,13 @@ def verify_kodi_defaults():
|
|||
|
||||
''' Make sure we have the kodi default folder in place.
|
||||
'''
|
||||
node_path = xbmc.translatePath("special://profile/library/video").decode('utf-8')
|
||||
node_path = xbmc.translatePath("special://profile/library/video")
|
||||
|
||||
if not xbmcvfs.exists(node_path):
|
||||
try:
|
||||
shutil.copytree(
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
|
||||
dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video"),
|
||||
dst=xbmc.translatePath("special://profile/library/video"))
|
||||
except Exception as error:
|
||||
LOG.warning(error)
|
||||
xbmcvfs.mkdir(node_path)
|
||||
|
@ -129,7 +129,7 @@ def verify_kodi_defaults():
|
|||
indent(xml)
|
||||
write_xml(etree.tostring(xml, 'UTF-8'), file)
|
||||
|
||||
playlist_path = xbmc.translatePath("special://profile/playlists/video").decode('utf-8')
|
||||
playlist_path = xbmc.translatePath("special://profile/playlists/video")
|
||||
|
||||
if not xbmcvfs.exists(playlist_path):
|
||||
xbmcvfs.mkdirs(playlist_path)
|
||||
|
@ -223,8 +223,8 @@ class Views(object):
|
|||
|
||||
''' Set up playlists, video nodes, window prop.
|
||||
'''
|
||||
node_path = xbmc.translatePath("special://profile/library/video").decode('utf-8')
|
||||
playlist_path = xbmc.translatePath("special://profile/playlists/video").decode('utf-8')
|
||||
node_path = xbmc.translatePath("special://profile/library/video")
|
||||
playlist_path = xbmc.translatePath("special://profile/playlists/video")
|
||||
index = 0
|
||||
|
||||
with Database('jellyfin') as jellyfindb:
|
||||
|
@ -779,16 +779,16 @@ class Views(object):
|
|||
|
||||
window_prop = "Jellyfin.nodes.%s" % index
|
||||
window('%s.index' % window_prop, path.replace('all.xml', "")) # dir
|
||||
window('%s.title' % window_prop, view['Name'].encode('utf-8'))
|
||||
window('%s.title' % window_prop, view['Name'])
|
||||
window('%s.content' % window_prop, path)
|
||||
|
||||
elif node == 'browse':
|
||||
|
||||
window_prop = "Jellyfin.nodes.%s" % index
|
||||
window('%s.title' % window_prop, view['Name'].encode('utf-8'))
|
||||
window('%s.title' % window_prop, view['Name'])
|
||||
else:
|
||||
window_prop = "Jellyfin.nodes.%s.%s" % (index, node)
|
||||
window('%s.title' % window_prop, node_label.encode('utf-8'))
|
||||
window('%s.title' % window_prop, node_label)
|
||||
window('%s.content' % window_prop, path)
|
||||
|
||||
window('%s.id' % window_prop, view['Id'])
|
||||
|
@ -831,17 +831,17 @@ class Views(object):
|
|||
|
||||
window_prop = "Jellyfin.wnodes.%s" % index
|
||||
window('%s.index' % window_prop, path.replace('all.xml', "")) # dir
|
||||
window('%s.title' % window_prop, view['Name'].encode('utf-8'))
|
||||
window('%s.title' % window_prop, view['Name'])
|
||||
window('%s.content' % window_prop, path)
|
||||
|
||||
elif node == 'browse':
|
||||
|
||||
window_prop = "Jellyfin.wnodes.%s" % index
|
||||
window('%s.title' % window_prop, view['Name'].encode('utf-8'))
|
||||
window('%s.title' % window_prop, view['Name'])
|
||||
window('%s.content' % window_prop, path)
|
||||
else:
|
||||
window_prop = "Jellyfin.wnodes.%s.%s" % (index, node)
|
||||
window('%s.title' % window_prop, node_label.encode('utf-8'))
|
||||
window('%s.title' % window_prop, node_label)
|
||||
window('%s.content' % window_prop, path)
|
||||
|
||||
window('%s.id' % window_prop, view['Id'])
|
||||
|
@ -881,7 +881,7 @@ class Views(object):
|
|||
'mode': "nextepisodes",
|
||||
'limit': self.limit
|
||||
}
|
||||
return "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
return "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
|
||||
def window_browse(self, view, node=None):
|
||||
|
||||
|
@ -896,7 +896,7 @@ class Views(object):
|
|||
if node:
|
||||
params['folder'] = node
|
||||
|
||||
return "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params))
|
||||
return "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params))
|
||||
|
||||
def window_clear(self, name=None):
|
||||
|
||||
|
@ -932,23 +932,23 @@ class Views(object):
|
|||
|
||||
''' Remove all jellyfin playlists.
|
||||
'''
|
||||
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/playlists/video/")
|
||||
_, files = xbmcvfs.listdir(path)
|
||||
for file in files:
|
||||
if file.decode('utf-8').startswith('jellyfin'):
|
||||
self.delete_playlist(os.path.join(path, file.decode('utf-8')))
|
||||
if file.startswith('jellyfin'):
|
||||
self.delete_playlist(os.path.join(path, file))
|
||||
|
||||
def delete_playlist_by_id(self, view_id):
|
||||
|
||||
''' Remove playlist based based on view_id.
|
||||
'''
|
||||
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/playlists/video/")
|
||||
_, files = xbmcvfs.listdir(path)
|
||||
for file in files:
|
||||
file = file.decode('utf-8')
|
||||
file = file
|
||||
|
||||
if file.startswith('jellyfin') and file.endswith('%s.xsp' % view_id):
|
||||
self.delete_playlist(os.path.join(path, file.decode('utf-8')))
|
||||
self.delete_playlist(os.path.join(path, file))
|
||||
|
||||
def delete_node(self, path):
|
||||
|
||||
|
@ -959,37 +959,37 @@ class Views(object):
|
|||
|
||||
''' Remove node and children files.
|
||||
'''
|
||||
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/library/video/")
|
||||
dirs, files = xbmcvfs.listdir(path)
|
||||
|
||||
for file in files:
|
||||
|
||||
if file.startswith('jellyfin'):
|
||||
self.delete_node(os.path.join(path, file.decode('utf-8')))
|
||||
self.delete_node(os.path.join(path, file))
|
||||
|
||||
for directory in dirs:
|
||||
|
||||
if directory.startswith('jellyfin'):
|
||||
_, files = xbmcvfs.listdir(os.path.join(path, directory.decode('utf-8')))
|
||||
_, files = xbmcvfs.listdir(os.path.join(path, directory))
|
||||
|
||||
for file in files:
|
||||
self.delete_node(os.path.join(path, directory.decode('utf-8'), file.decode('utf-8')))
|
||||
self.delete_node(os.path.join(path, directory, file))
|
||||
|
||||
xbmcvfs.rmdir(os.path.join(path, directory.decode('utf-8')))
|
||||
xbmcvfs.rmdir(os.path.join(path, directory))
|
||||
|
||||
def delete_node_by_id(self, view_id):
|
||||
|
||||
''' Remove node and children files based on view_id.
|
||||
'''
|
||||
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
||||
path = xbmc.translatePath("special://profile/library/video/")
|
||||
dirs, files = xbmcvfs.listdir(path)
|
||||
|
||||
for directory in dirs:
|
||||
|
||||
if directory.startswith('jellyfin') and directory.endswith(view_id):
|
||||
_, files = xbmcvfs.listdir(os.path.join(path, directory.decode('utf-8')))
|
||||
_, files = xbmcvfs.listdir(os.path.join(path, directory))
|
||||
|
||||
for file in files:
|
||||
self.delete_node(os.path.join(path, directory.decode('utf-8'), file.decode('utf-8')))
|
||||
self.delete_node(os.path.join(path, directory, file))
|
||||
|
||||
xbmcvfs.rmdir(os.path.join(path, directory.decode('utf-8')))
|
||||
xbmcvfs.rmdir(os.path.join(path, directory))
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import BaseHTTPServer
|
||||
from six.moves import BaseHTTPServer
|
||||
import logging
|
||||
import httplib
|
||||
from six.moves import http_client as httplib
|
||||
import threading
|
||||
import urlparse
|
||||
from six.moves.urllib.parse import parse_qsl
|
||||
|
||||
import xbmc
|
||||
from kodi_six import xbmc
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -97,7 +98,7 @@ class requestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
if '?' in path:
|
||||
path = path.split('?', 1)[1]
|
||||
|
||||
params = dict(urlparse.parse_qsl(path))
|
||||
params = dict(parse_qsl(path))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
|
|
14
service.py
14
service.py
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -7,13 +8,12 @@ import os
|
|||
import threading
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
#################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi')).decode('utf-8')
|
||||
__base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'jellyfin_kodi'))
|
||||
|
||||
sys.path.insert(0, __base__)
|
||||
|
||||
|
@ -54,11 +54,11 @@ class ServiceManager(threading.Thread):
|
|||
LOG.exception(error)
|
||||
|
||||
if service is not None:
|
||||
|
||||
if 'ExitService' not in error:
|
||||
# TODO: fix this properly as to not match on str()
|
||||
if 'ExitService' not in str(error):
|
||||
service.shutdown()
|
||||
|
||||
if 'RestartService' in error:
|
||||
if 'RestartService' in str(error):
|
||||
service.reload_objects()
|
||||
|
||||
self.exception = error
|
||||
|
@ -79,7 +79,7 @@ if __name__ == "__main__":
|
|||
session.start()
|
||||
session.join() # Block until the thread exits.
|
||||
|
||||
if 'RestartService' in session.exception:
|
||||
if 'RestartService' in str(session.exception):
|
||||
continue
|
||||
|
||||
except Exception as error:
|
||||
|
|
Loading…
Add table
Reference in a new issue