diff --git a/.env b/.env
new file mode 100644
index 00000000..a8471c01
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+PYTHONPATH=jellyfin_kodi
diff --git a/.gitignore b/.gitignore
index 9547020e..b344f958 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.pyo
+__pycache__/
__local__/
machine_guid
/resources/media/Thumbs.db
diff --git a/addon.xml b/addon.xml
index b3ab49cc..557bd9bb 100644
--- a/addon.xml
+++ b/addon.xml
@@ -7,6 +7,8 @@
+
+
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:
diff --git a/jellyfin_kodi/database/jellyfin_db.py b/jellyfin_kodi/database/jellyfin_db.py
index ca9cb50b..3367ab51 100644
--- a/jellyfin_kodi/database/jellyfin_db.py
+++ b/jellyfin_kodi/database/jellyfin_db.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/database/queries.py b/jellyfin_kodi/database/queries.py
index 0efc1c75..66582caf 100644
--- a/jellyfin_kodi/database/queries.py
+++ b/jellyfin_kodi/database/queries.py
@@ -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,
diff --git a/jellyfin_kodi/dialogs/__init__.py b/jellyfin_kodi/dialogs/__init__.py
index 5b9b227f..94a8b89c 100644
--- a/jellyfin_kodi/dialogs/__init__.py
+++ b/jellyfin_kodi/dialogs/__init__.py
@@ -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
diff --git a/jellyfin_kodi/dialogs/context.py b/jellyfin_kodi/dialogs/context.py
index 63ba0052..454f9275 100644
--- a/jellyfin_kodi/dialogs/context.py
+++ b/jellyfin_kodi/dialogs/context.py
@@ -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
diff --git a/jellyfin_kodi/dialogs/loginmanual.py b/jellyfin_kodi/dialogs/loginmanual.py
index 3a07c809..c93326d1 100644
--- a/jellyfin_kodi/dialogs/loginmanual.py
+++ b/jellyfin_kodi/dialogs/loginmanual.py
@@ -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):
diff --git a/jellyfin_kodi/dialogs/resume.py b/jellyfin_kodi/dialogs/resume.py
index ef10f353..716cda4e 100644
--- a/jellyfin_kodi/dialogs/resume.py
+++ b/jellyfin_kodi/dialogs/resume.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/dialogs/serverconnect.py b/jellyfin_kodi/dialogs/serverconnect.py
index ef7cb133..101dcd4e 100644
--- a/jellyfin_kodi/dialogs/serverconnect.py
+++ b/jellyfin_kodi/dialogs/serverconnect.py
@@ -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):
diff --git a/jellyfin_kodi/dialogs/servermanual.py b/jellyfin_kodi/dialogs/servermanual.py
index 2e06e952..c1970fa5 100644
--- a/jellyfin_kodi/dialogs/servermanual.py
+++ b/jellyfin_kodi/dialogs/servermanual.py
@@ -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):
diff --git a/jellyfin_kodi/dialogs/usersconnect.py b/jellyfin_kodi/dialogs/usersconnect.py
index 4cf02b62..023f85be 100644
--- a/jellyfin_kodi/dialogs/usersconnect.py
+++ b/jellyfin_kodi/dialogs/usersconnect.py
@@ -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):
diff --git a/jellyfin_kodi/downloader.py b/jellyfin_kodi/downloader.py
index 54ace2ef..2a94c698 100644
--- a/jellyfin_kodi/downloader.py
+++ b/jellyfin_kodi/downloader.py
@@ -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
diff --git a/jellyfin_kodi/entrypoint/__init__.py b/jellyfin_kodi/entrypoint/__init__.py
index a55c913d..23cc4476 100644
--- a/jellyfin_kodi/entrypoint/__init__.py
+++ b/jellyfin_kodi/entrypoint/__init__.py
@@ -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
diff --git a/jellyfin_kodi/entrypoint/context.py b/jellyfin_kodi/entrypoint/context.py
index 337ebf36..01b5f801 100644
--- a/jellyfin_kodi/entrypoint/context.py
+++ b/jellyfin_kodi/entrypoint/context.py
@@ -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']})
diff --git a/jellyfin_kodi/entrypoint/default.py b/jellyfin_kodi/entrypoint/default.py
index 03e77ae2..ba8a7573 100644
--- a/jellyfin_kodi/entrypoint/default.py
+++ b/jellyfin_kodi/entrypoint/default.py
@@ -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)
diff --git a/jellyfin_kodi/entrypoint/service.py b/jellyfin_kodi/entrypoint/service.py
index 58fb8ef0..b3b0ed2b 100644
--- a/jellyfin_kodi/entrypoint/service.py
+++ b/jellyfin_kodi/entrypoint/service.py
@@ -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)
diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py
index 5138dd00..a3226a65 100644
--- a/jellyfin_kodi/full_sync.py
+++ b/jellyfin_kodi/full_sync.py
@@ -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
diff --git a/jellyfin_kodi/helper/__init__.py b/jellyfin_kodi/helper/__init__.py
index a9db000e..77d13ad1 100644
--- a/jellyfin_kodi/helper/__init__.py
+++ b/jellyfin_kodi/helper/__init__.py
@@ -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
diff --git a/jellyfin_kodi/helper/api.py b/jellyfin_kodi/helper/api.py
index e00acc00..2a175455 100644
--- a/jellyfin_kodi/helper/api.py
+++ b/jellyfin_kodi/helper/api.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
##################################################################################################
diff --git a/jellyfin_kodi/helper/exceptions.py b/jellyfin_kodi/helper/exceptions.py
index c2ed4685..c7ca2291 100644
--- a/jellyfin_kodi/helper/exceptions.py
+++ b/jellyfin_kodi/helper/exceptions.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
diff --git a/jellyfin_kodi/helper/loghandler.py b/jellyfin_kodi/helper/loghandler.py
index 8fe0ea17..c067a960 100644
--- a/jellyfin_kodi/helper/loghandler.py
+++ b/jellyfin_kodi/helper/loghandler.py
@@ -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):
diff --git a/jellyfin_kodi/helper/playutils.py b/jellyfin_kodi/helper/playutils.py
index 82b77a68..d4fbaec8 100644
--- a/jellyfin_kodi/helper/playutils.py
+++ b/jellyfin_kodi/helper/playutils.py
@@ -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)
diff --git a/jellyfin_kodi/helper/translate.py b/jellyfin_kodi/helper/translate.py
index 8059d377..d140b149 100644
--- a/jellyfin_kodi/helper/translate.py
+++ b/jellyfin_kodi/helper/translate.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/helper/utils.py b/jellyfin_kodi/helper/utils.py
index f6ca9320..67d4ecd2 100644
--- a/jellyfin_kodi/helper/utils.py
+++ b/jellyfin_kodi/helper/utils.py
@@ -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)
diff --git a/jellyfin_kodi/helper/wrapper.py b/jellyfin_kodi/helper/wrapper.py
index 746fed5e..ccd49bdd 100644
--- a/jellyfin_kodi/helper/wrapper.py
+++ b/jellyfin_kodi/helper/wrapper.py
@@ -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
diff --git a/jellyfin_kodi/helper/xmls.py b/jellyfin_kodi/helper/xmls.py
index cb0d8f39..62b6058c 100644
--- a/jellyfin_kodi/helper/xmls.py
+++ b/jellyfin_kodi/helper/xmls.py
@@ -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:
diff --git a/jellyfin_kodi/jellyfin/__init__.py b/jellyfin_kodi/jellyfin/__init__.py
index cffb1e6a..19dba025 100644
--- a/jellyfin_kodi/jellyfin/__init__.py
+++ b/jellyfin_kodi/jellyfin/__init__.py
@@ -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
#################################################################################################
diff --git a/jellyfin_kodi/jellyfin/api.py b/jellyfin_kodi/jellyfin/api.py
index 4eab6872..ba43c4cd 100644
--- a/jellyfin_kodi/jellyfin/api.py
+++ b/jellyfin_kodi/jellyfin/api.py
@@ -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)
diff --git a/jellyfin_kodi/jellyfin/client.py b/jellyfin_kodi/jellyfin/client.py
index ee9db7fd..d326f409 100644
--- a/jellyfin_kodi/jellyfin/client.py
+++ b/jellyfin_kodi/jellyfin/client.py
@@ -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
#################################################################################################
diff --git a/jellyfin_kodi/jellyfin/configuration.py b/jellyfin_kodi/jellyfin/configuration.py
index 06e50088..b73f23ca 100644
--- a/jellyfin_kodi/jellyfin/configuration.py
+++ b/jellyfin_kodi/jellyfin/configuration.py
@@ -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.
diff --git a/jellyfin_kodi/jellyfin/connection_manager.py b/jellyfin_kodi/jellyfin/connection_manager.py
index c3195e49..2b0e4780 100644
--- a/jellyfin_kodi/jellyfin/connection_manager.py
+++ b/jellyfin_kodi/jellyfin/connection_manager.py
@@ -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 = ("", 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
diff --git a/jellyfin_kodi/jellyfin/credentials.py b/jellyfin_kodi/jellyfin/credentials.py
index 0b61f3dd..2eeacb98 100644
--- a/jellyfin_kodi/jellyfin/credentials.py
+++ b/jellyfin_kodi/jellyfin/credentials.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
diff --git a/jellyfin_kodi/jellyfin/exceptions.py b/jellyfin_kodi/jellyfin/exceptions.py
index aea09675..6cd50511 100644
--- a/jellyfin_kodi/jellyfin/exceptions.py
+++ b/jellyfin_kodi/jellyfin/exceptions.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
diff --git a/jellyfin_kodi/jellyfin/http.py b/jellyfin_kodi/jellyfin/http.py
index 87756e54..f4cae0d3 100644
--- a/jellyfin_kodi/jellyfin/http.py
+++ b/jellyfin_kodi/jellyfin/http.py
@@ -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
diff --git a/jellyfin_kodi/jellyfin/websocket.py b/jellyfin_kodi/jellyfin/websocket.py
index 6cb9c009..2c6a706f 100644
--- a/jellyfin_kodi/jellyfin/websocket.py
+++ b/jellyfin_kodi/jellyfin/websocket.py
@@ -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 = []
diff --git a/jellyfin_kodi/jellyfin/ws_client.py b/jellyfin_kodi/jellyfin/ws_client.py
index a19d624d..da2efcbf 100644
--- a/jellyfin_kodi/jellyfin/ws_client.py
+++ b/jellyfin_kodi/jellyfin/ws_client.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/library.py b/jellyfin_kodi/library.py
index 0d67c318..33ad98f6 100644
--- a/jellyfin_kodi/library.py
+++ b/jellyfin_kodi/library.py
@@ -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:
diff --git a/jellyfin_kodi/monitor.py b/jellyfin_kodi/monitor.py
index 1a8b1d5e..a423303e 100644
--- a/jellyfin_kodi/monitor.py
+++ b/jellyfin_kodi/monitor.py
@@ -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)
diff --git a/jellyfin_kodi/objects/__init__.py b/jellyfin_kodi/objects/__init__.py
index 6d3c8152..469f3809 100644
--- a/jellyfin_kodi/objects/__init__.py
+++ b/jellyfin_kodi/objects/__init__.py
@@ -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()
diff --git a/jellyfin_kodi/objects/actions.py b/jellyfin_kodi/objects/actions.py
index 394d9e2c..6313a446 100644
--- a/jellyfin_kodi/objects/actions.py
+++ b/jellyfin_kodi/objects/actions.py
@@ -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
diff --git a/jellyfin_kodi/objects/kodi/__init__.py b/jellyfin_kodi/objects/kodi/__init__.py
index 86ada83f..961219bf 100644
--- a/jellyfin_kodi/objects/kodi/__init__.py
+++ b/jellyfin_kodi/objects/kodi/__init__.py
@@ -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
diff --git a/jellyfin_kodi/objects/kodi/artwork.py b/jellyfin_kodi/objects/kodi/artwork.py
index 9de81a51..0625d75e 100644
--- a/jellyfin_kodi/objects/kodi/artwork.py
+++ b/jellyfin_kodi/objects/kodi/artwork.py
@@ -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)
diff --git a/jellyfin_kodi/objects/kodi/kodi.py b/jellyfin_kodi/objects/kodi/kodi.py
index 844d3ca4..e34d57d2 100644
--- a/jellyfin_kodi/objects/kodi/kodi.py
+++ b/jellyfin_kodi/objects/kodi/kodi.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/objects/kodi/movies.py b/jellyfin_kodi/objects/kodi/movies.py
index 38fd9329..40c442a1 100644
--- a/jellyfin_kodi/objects/kodi/movies.py
+++ b/jellyfin_kodi/objects/kodi/movies.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/objects/kodi/music.py b/jellyfin_kodi/objects/kodi/music.py
index 6b676b1d..89213e94 100644
--- a/jellyfin_kodi/objects/kodi/music.py
+++ b/jellyfin_kodi/objects/kodi/music.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/objects/kodi/musicvideos.py b/jellyfin_kodi/objects/kodi/musicvideos.py
index 764a79ba..70de6cdf 100644
--- a/jellyfin_kodi/objects/kodi/musicvideos.py
+++ b/jellyfin_kodi/objects/kodi/musicvideos.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/objects/kodi/queries.py b/jellyfin_kodi/objects/kodi/queries.py
index 75fb15da..fea7dba6 100644
--- a/jellyfin_kodi/objects/kodi/queries.py
+++ b/jellyfin_kodi/objects/kodi/queries.py
@@ -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
diff --git a/jellyfin_kodi/objects/kodi/queries_music.py b/jellyfin_kodi/objects/kodi/queries_music.py
index b9105a7a..836883bc 100644
--- a/jellyfin_kodi/objects/kodi/queries_music.py
+++ b/jellyfin_kodi/objects/kodi/queries_music.py
@@ -1,3 +1,4 @@
+from __future__ import division, absolute_import, print_function, unicode_literals
create_artist = """
SELECT coalesce(max(idArtist), 1)
diff --git a/jellyfin_kodi/objects/kodi/queries_texture.py b/jellyfin_kodi/objects/kodi/queries_texture.py
index 25960941..d60505b7 100644
--- a/jellyfin_kodi/objects/kodi/queries_texture.py
+++ b/jellyfin_kodi/objects/kodi/queries_texture.py
@@ -1,3 +1,4 @@
+from __future__ import division, absolute_import, print_function, unicode_literals
get_cache = """
SELECT cachedurl
diff --git a/jellyfin_kodi/objects/kodi/tvshows.py b/jellyfin_kodi/objects/kodi/tvshows.py
index 4d620e87..b9feda4d 100644
--- a/jellyfin_kodi/objects/kodi/tvshows.py
+++ b/jellyfin_kodi/objects/kodi/tvshows.py
@@ -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
##################################################################################################
diff --git a/jellyfin_kodi/objects/movies.py b/jellyfin_kodi/objects/movies.py
index ffb57906..5cd8f3ab 100644
--- a/jellyfin_kodi/objects/movies.py
+++ b/jellyfin_kodi/objects/movies.py
@@ -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()
diff --git a/jellyfin_kodi/objects/music.py b/jellyfin_kodi/objects/music.py
index 81f37e9c..be8b5922 100644
--- a/jellyfin_kodi/objects/music.py
+++ b/jellyfin_kodi/objects/music.py
@@ -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
diff --git a/jellyfin_kodi/objects/musicvideos.py b/jellyfin_kodi/objects/musicvideos.py
index fe24e6cc..b4cca7b2 100644
--- a/jellyfin_kodi/objects/musicvideos.py
+++ b/jellyfin_kodi/objects/musicvideos.py
@@ -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()
diff --git a/jellyfin_kodi/objects/obj.py b/jellyfin_kodi/objects/obj.py
index ac1a7aa2..1cca13e4 100644
--- a/jellyfin_kodi/objects/obj.py
+++ b/jellyfin_kodi/objects/obj.py
@@ -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
diff --git a/jellyfin_kodi/objects/tvshows.py b/jellyfin_kodi/objects/tvshows.py
index 9922641d..9eedf007 100644
--- a/jellyfin_kodi/objects/tvshows.py
+++ b/jellyfin_kodi/objects/tvshows.py
@@ -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))
diff --git a/jellyfin_kodi/objects/utils.py b/jellyfin_kodi/objects/utils.py
index f0da50c8..cbed4e74 100644
--- a/jellyfin_kodi/objects/utils.py
+++ b/jellyfin_kodi/objects/utils.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
diff --git a/jellyfin_kodi/player.py b/jellyfin_kodi/player.py
index 0d342058..cd758fb1 100644
--- a/jellyfin_kodi/player.py
+++ b/jellyfin_kodi/player.py
@@ -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 {}
diff --git a/jellyfin_kodi/setup.py b/jellyfin_kodi/setup.py
index 77cce34b..3305c485 100644
--- a/jellyfin_kodi/setup.py
+++ b/jellyfin_kodi/setup.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
diff --git a/jellyfin_kodi/views.py b/jellyfin_kodi/views.py
index a236ed58..b75063f7 100644
--- a/jellyfin_kodi/views.py
+++ b/jellyfin_kodi/views.py
@@ -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))
diff --git a/jellyfin_kodi/webservice.py b/jellyfin_kodi/webservice.py
index dc68e69a..db63a07a 100644
--- a/jellyfin_kodi/webservice.py
+++ b/jellyfin_kodi/webservice.py
@@ -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 = {}
diff --git a/service.py b/service.py
index f807e14f..a1951880 100644
--- a/service.py
+++ b/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: