From 168bab2b01bed17e3e2ac51987e5d88634f49db1 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Thu, 31 Jan 2019 23:23:55 +0100 Subject: [PATCH] Rebrand addon name and id and make it compatible with Jellyfin --- .gitignore | 1 + addon.xml | 24 ++--- context.py | 2 +- context_play.py | 2 +- default.py | 2 +- icon.png | Bin 1850 -> 40709 bytes .../resource.language.de_de/strings.po | 2 +- .../resource.language.en_gb/strings.po | 2 +- .../resource.language.fr_fr/strings.po | 2 +- .../resource.language.it_it/strings.po | 2 +- .../resource.language.nl_nl/strings.po | 2 +- .../resource.language.pl_pl/strings.po | 2 +- resources/lib/client.py | 2 +- resources/lib/database/__init__.py | 10 +-- resources/lib/downloader.py | 2 +- resources/lib/emby/core/connection_manager.py | 2 +- resources/lib/entrypoint/context.py | 4 +- resources/lib/entrypoint/default.py | 84 +++++++++--------- resources/lib/entrypoint/service.py | 7 +- resources/lib/helper/playutils.py | 2 +- resources/lib/helper/translate.py | 2 +- resources/lib/helper/utils.py | 6 +- resources/lib/monitor.py | 8 +- resources/lib/objects/actions.py | 14 +-- resources/lib/objects/movies.py | 4 +- resources/lib/objects/musicvideos.py | 2 +- resources/lib/objects/tvshows.py | 10 +-- resources/lib/player.py | 2 +- resources/lib/views.py | 6 +- resources/lib/webservice.py | 2 +- resources/settings.xml | 16 ++-- .../script-emby-connect-login-manual.xml | 10 +-- .../1080i/script-emby-connect-login.xml | 14 +-- .../script-emby-connect-server-manual.xml | 10 +-- .../1080i/script-emby-connect-server.xml | 8 +- .../1080i/script-emby-connect-users.xml | 6 +- service.py | 2 +- 37 files changed, 136 insertions(+), 142 deletions(-) diff --git a/.gitignore b/.gitignore index 959fc2ad..c0132b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ machine_guid /resources/media/Thumbs.db .idea/ +.DS_Store diff --git a/addon.xml b/addon.xml index d355868e..c5f9cded 100644 --- a/addon.xml +++ b/addon.xml @@ -1,13 +1,10 @@ - - - - @@ -31,18 +28,13 @@ all en GNU GENERAL PUBLIC LICENSE. Version 2, June 1991 - http://emby.media/community/index.php?/forum/99-kodi/ - http://emby.media/ - https://github.com/MediaBrowser/plugin.video.emby + https://forum.jellyfin.org + https://jellyfin.media/ + https://github.com/jellyfin/jellyfin-kodi - Welcome to Emby for Kodi A whole new way to manage and view your media library. The Emby addon for Kodi combines the best of Kodi - ultra smooth navigation, beautiful UIs and playback of any file under the sun, and Emby - the most powerful fully open source multi-client media metadata indexer and server. Emby for Kodi is the absolute best way to enjoy the incredible Kodi playback engine combined with the power of Emby's centralized database. Features: Direct integration with the Kodi library for native Kodi speed Instant synchronization with the Emby server Full support for Movie, TV and Music collections Emby Server direct stream and transcoding support - use Kodi when you are away from home! + Welcome to Jellyfin for Kodi A whole new way to manage and view your media library. The Jellyfin addon for Kodi combines the best of Kodi - ultra smooth navigation, beautiful UIs and playback of any file under the sun, and Jellyfin - the most powerful fully open source multi-client media metadata indexer and server. Jellyfin for Kodi is the absolute best way to enjoy the incredible Kodi playback engine combined with the power of Jellyfin's centralized database. Features: Direct integration with the Kodi library for native Kodi speed Instant synchronization with the Jellyfin server Full support for Movie, TV and Music collections Jellyfin Server direct stream and transcoding support - use Kodi when you are away from home! - New stable release - The wiki has been updated, PLEASE READ: https://github.com/MediaBrowser/plugin.video.emby/wiki - Fix playback for Kodi Leia - Fix masterlock - Home videos and pictures now show under videos and picture add-ons - Dependencies were updated to 0.14! + Rebrand in progress diff --git a/context.py b/context.py index 3a89a817..fdec02ad 100644 --- a/context.py +++ b/context.py @@ -11,7 +11,7 @@ import xbmcaddon ################################################################################################# -__addon__ = xbmcaddon.Addon(id='plugin.video.emby') +__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin') __base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'resources', 'lib')).decode('utf-8') __libraries__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'libraries')).decode('utf-8') __pcache__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('profile'), 'emby')).decode('utf-8') diff --git a/context_play.py b/context_play.py index 58ee93fb..6ed686cc 100644 --- a/context_play.py +++ b/context_play.py @@ -11,7 +11,7 @@ import xbmcaddon ################################################################################################# -__addon__ = xbmcaddon.Addon(id='plugin.video.emby') +__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin') __base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'resources', 'lib')).decode('utf-8') __libraries__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'libraries')).decode('utf-8') __pcache__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('profile'), 'emby')).decode('utf-8') diff --git a/default.py b/default.py index 6f1b05a0..8092bb94 100644 --- a/default.py +++ b/default.py @@ -11,7 +11,7 @@ import xbmcaddon ################################################################################################# -__addon__ = xbmcaddon.Addon(id='plugin.video.emby') +__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin') __base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'resources', 'lib')).decode('utf-8') __libraries__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'libraries')).decode('utf-8') __pcache__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('profile'), 'emby')).decode('utf-8') diff --git a/icon.png b/icon.png index cb7c85caf3cba44da1dd5bb456035b7622204ff4..6360cfab34c543d457a2d69b2a03ae2ee7ce163b 100644 GIT binary patch literal 40709 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, 2018 diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 897396a3..d0408eb8 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -1,6 +1,6 @@ # Emby for Kodi language file # Addon Name: Emby for Kodi -# Addon id: plugin.video.emby +# Addon id: plugin.video.jellyfin # Addon Provider: angelblue05 msgid "" msgstr "" diff --git a/resources/language/resource.language.fr_fr/strings.po b/resources/language/resource.language.fr_fr/strings.po index 356133c1..03a1a716 100644 --- a/resources/language/resource.language.fr_fr/strings.po +++ b/resources/language/resource.language.fr_fr/strings.po @@ -1,6 +1,6 @@ # Emby for Kodi language file # Addon Name: Emby for Kodi -# Addon id: plugin.video.emby +# Addon id: plugin.video.jellyfin # Addon Provider: angelblue05 # Translators: # Jean Fontaine , 2018 diff --git a/resources/language/resource.language.it_it/strings.po b/resources/language/resource.language.it_it/strings.po index e94cf631..b4e2d650 100644 --- a/resources/language/resource.language.it_it/strings.po +++ b/resources/language/resource.language.it_it/strings.po @@ -1,6 +1,6 @@ # Emby for Kodi language file # Addon Name: Emby for Kodi -# Addon id: plugin.video.emby +# Addon id: plugin.video.jellyfin # Addon Provider: angelblue05 # Translators: # EffeF, 2019 diff --git a/resources/language/resource.language.nl_nl/strings.po b/resources/language/resource.language.nl_nl/strings.po index 724b877c..732a7d13 100644 --- a/resources/language/resource.language.nl_nl/strings.po +++ b/resources/language/resource.language.nl_nl/strings.po @@ -1,6 +1,6 @@ # Emby for Kodi language file # Addon Name: Emby for Kodi -# Addon id: plugin.video.emby +# Addon id: plugin.video.jellyfin # Addon Provider: angelblue05 # Translators: # 63ac71fcbd0581bb567b1f0d798c7970, 2019 diff --git a/resources/language/resource.language.pl_pl/strings.po b/resources/language/resource.language.pl_pl/strings.po index 7877ad59..8170e3e2 100644 --- a/resources/language/resource.language.pl_pl/strings.po +++ b/resources/language/resource.language.pl_pl/strings.po @@ -1,6 +1,6 @@ # Emby for Kodi language file # Addon Name: Emby for Kodi -# Addon id: plugin.video.emby +# Addon id: plugin.video.jellyfin # Addon Provider: angelblue05 # Translators: # MichaƂ Sawicz , 2019 diff --git a/resources/lib/client.py b/resources/lib/client.py index 8f523448..6c2b1a15 100644 --- a/resources/lib/client.py +++ b/resources/lib/client.py @@ -82,7 +82,7 @@ def get_device_id(reset=False): if client_id: return client_id - directory = xbmc.translatePath('special://profile/addon_data/plugin.video.emby/').decode('utf-8') + directory = xbmc.translatePath('special://profile/addon_data/plugin.video.jellyfin/').decode('utf-8') if not xbmcvfs.exists(directory): xbmcvfs.mkdir(directory) diff --git a/resources/lib/database/__init__.py b/resources/lib/database/__init__.py index 6ed45e6a..b6161cb8 100644 --- a/resources/lib/database/__init__.py +++ b/resources/lib/database/__init__.py @@ -238,7 +238,7 @@ def reset(): if dialog("yesno", heading="{emby}", line1=_(33086)): reset_artwork() - addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/").decode('utf-8') + addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8') if dialog("yesno", heading="{emby}", line1=_(33087)): @@ -326,7 +326,7 @@ def reset_artwork(): def get_sync(): - path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/").decode('utf-8') + path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8') if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) @@ -346,7 +346,7 @@ def get_sync(): def save_sync(sync): - path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/").decode('utf-8') + path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8') if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) @@ -358,7 +358,7 @@ def save_sync(sync): def get_credentials(): - path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/").decode('utf-8') + path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8') if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) @@ -384,7 +384,7 @@ def get_credentials(): def save_credentials(credentials): credentials = credentials or {} - path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/").decode('utf-8') + path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/").decode('utf-8') if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) diff --git a/resources/lib/downloader.py b/resources/lib/downloader.py index 43c43d1c..6cc5c35c 100644 --- a/resources/lib/downloader.py +++ b/resources/lib/downloader.py @@ -24,7 +24,7 @@ from emby.core.exceptions import HTTPException LOG = logging.getLogger("EMBY."+__name__) LIMIT = min(int(settings('limitIndex') or 50), 50) -CACHE = xbmc.translatePath(os.path.join(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile').decode('utf-8'), 'emby')).decode('utf-8') +CACHE = xbmc.translatePath(os.path.join(xbmcaddon.Addon(id='plugin.video.jellyfin').getAddonInfo('profile').decode('utf-8'), 'emby')).decode('utf-8') ################################################################################################# diff --git a/resources/lib/emby/core/connection_manager.py b/resources/lib/emby/core/connection_manager.py index 62b3dce3..85e9ff4a 100644 --- a/resources/lib/emby/core/connection_manager.py +++ b/resources/lib/emby/core/connection_manager.py @@ -43,7 +43,7 @@ def get_server_address(server, mode): class ConnectionManager(object): - min_server_version = "3.0.5930" + min_server_version = "10.1.0" server_version = min_server_version user = {} server_id = None diff --git a/resources/lib/entrypoint/context.py b/resources/lib/entrypoint/context.py index d5078eed..f45bb06c 100644 --- a/resources/lib/entrypoint/context.py +++ b/resources/lib/entrypoint/context.py @@ -18,7 +18,7 @@ from objects import Actions ################################################################################################# LOG = logging.getLogger("EMBY."+__name__) -XML_PATH = (xbmcaddon.Addon('plugin.video.emby').getAddonInfo('path'), "default", "1080i") +XML_PATH = (xbmcaddon.Addon('plugin.video.jellyfin').getAddonInfo('path'), "default", "1080i") OPTIONS = { 'Refresh': _(30410), 'Delete': _(30409), @@ -153,7 +153,7 @@ class Context(object): TheVoid('FavoriteItem', {'ServerId': self.server, 'Id': self.item['Id'], 'Favorite': False}) elif selected == OPTIONS['Addon']: - xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)') + xbmc.executebuiltin('Addon.OpenSettings(plugin.video.jellyfin)') elif selected == OPTIONS['Delete']: self.delete_item() diff --git a/resources/lib/entrypoint/default.py b/resources/lib/entrypoint/default.py index 3c46a911..43d43e84 100644 --- a/resources/lib/entrypoint/default.py +++ b/resources/lib/entrypoint/default.py @@ -109,7 +109,7 @@ class Events(object): elif mode == 'removeserver': event('RemoveServer', {'Id': server}) elif mode == 'settings': - xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)') + xbmc.executebuiltin('Addon.OpenSettings(plugin.video.jellyfin)') elif mode == 'adduser': add_user() elif mode == 'checkupdate': @@ -153,13 +153,13 @@ def listing(): if view_id and node in ('movies', 'tvshows', 'musicvideos', 'music', 'mixed') and view_id not in whitelist: label = "%s %s" % (label.decode('utf-8'), _(33166)) - context.append((_(33123), "RunPlugin(plugin://plugin.video.emby/?mode=synclib&id=%s)" % view_id)) + context.append((_(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: - context.append((_(33136), "RunPlugin(plugin://plugin.video.emby/?mode=updatelib&id=%s)" % view_id)) - context.append((_(33132), "RunPlugin(plugin://plugin.video.emby/?mode=repairlib&id=%s)" % view_id)) - context.append((_(33133), "RunPlugin(plugin://plugin.video.emby/?mode=removelib&id=%s)" % view_id)) + context.append((_(33136), "RunPlugin(plugin://plugin.video.jellyfin/?mode=updatelib&id=%s)" % view_id)) + context.append((_(33132), "RunPlugin(plugin://plugin.video.jellyfin/?mode=repairlib&id=%s)" % view_id)) + context.append((_(33133), "RunPlugin(plugin://plugin.video.jellyfin/?mode=removelib&id=%s)" % view_id)) LOG.debug("--[ listing/%s/%s ] %s", node, label, path) @@ -177,25 +177,25 @@ def listing(): context = [] if server.get('ManualAddress'): - context.append((_(33141), "RunPlugin(plugin://plugin.video.emby/?mode=removeserver&server=%s)" % server['Id'])) + context.append((_(33141), "RunPlugin(plugin://plugin.video.jellyfin/?mode=removeserver&server=%s)" % server['Id'])) if 'AccessToken' not in server: - directory("%s (%s)" % (server['Name'], _(30539)), "plugin://plugin.video.emby/?mode=login&server=%s" % server['Id'], False, context=context) + directory("%s (%s)" % (server['Name'], _(30539)), "plugin://plugin.video.jellyfin/?mode=login&server=%s" % server['Id'], False, context=context) else: - directory(server['Name'], "plugin://plugin.video.emby/?mode=browse&server=%s" % server['Id'], context=context) + directory(server['Name'], "plugin://plugin.video.jellyfin/?mode=browse&server=%s" % server['Id'], context=context) - directory(_(33194), "plugin://plugin.video.emby/?mode=managelibs", True) - directory(_(33134), "plugin://plugin.video.emby/?mode=addserver", False) - directory(_(33054), "plugin://plugin.video.emby/?mode=adduser", False) - directory(_(5), "plugin://plugin.video.emby/?mode=settings", False) - directory(_(33058), "plugin://plugin.video.emby/?mode=reset", False) - directory(_(33192), "plugin://plugin.video.emby/?mode=restartservice", False) + directory(_(33194), "plugin://plugin.video.jellyfin/?mode=managelibs", True) + directory(_(33134), "plugin://plugin.video.jellyfin/?mode=addserver", False) + directory(_(33054), "plugin://plugin.video.jellyfin/?mode=adduser", False) + directory(_(5), "plugin://plugin.video.jellyfin/?mode=settings", False) + directory(_(33058), "plugin://plugin.video.jellyfin/?mode=reset", False) + directory(_(33192), "plugin://plugin.video.jellyfin/?mode=restartservice", False) if settings('backupPath'): - directory(_(33092), "plugin://plugin.video.emby/?mode=backup", False) + directory(_(33092), "plugin://plugin.video.jellyfin/?mode=backup", False) - directory(_(33163), None, False, artwork="special://home/addons/plugin.video.emby/donations.png") + directory(_(33163), None, False, artwork="special://home/addons/plugin.video.jellyfin/donations.png") xbmcplugin.setContent(int(sys.argv[1]), 'files') xbmcplugin.endOfDirectory(int(sys.argv[1])) @@ -216,20 +216,20 @@ def directory(label, path, folder=True, artwork=None, fanart=None, context=None) def dir_listitem(label, path, artwork=None, fanart=None): li = xbmcgui.ListItem(label, path=path) - li.setThumbnailImage(artwork or "special://home/addons/plugin.video.emby/icon.png") - li.setArt({"fanart": fanart or "special://home/addons/plugin.video.emby/fanart.jpg"}) - li.setArt({"landscape": artwork or fanart or "special://home/addons/plugin.video.emby/fanart.jpg"}) + li.setThumbnailImage(artwork or "special://home/addons/plugin.video.jellyfin/icon.png") + li.setArt({"fanart": fanart or "special://home/addons/plugin.video.jellyfin/fanart.jpg"}) + li.setArt({"landscape": artwork or fanart or "special://home/addons/plugin.video.jellyfin/fanart.jpg"}) return li def manage_libraries(): - directory(_(33098), "plugin://plugin.video.emby/?mode=refreshboxsets", False) - directory(_(33154), "plugin://plugin.video.emby/?mode=addlibs", False) - directory(_(33139), "plugin://plugin.video.emby/?mode=updatelibs", False) - directory(_(33140), "plugin://plugin.video.emby/?mode=repairlibs", False) - directory(_(33184), "plugin://plugin.video.emby/?mode=removelibs", False) - directory(_(33060), "plugin://plugin.video.emby/?mode=thememedia", False) + directory(_(33098), "plugin://plugin.video.jellyfin/?mode=refreshboxsets", False) + directory(_(33154), "plugin://plugin.video.jellyfin/?mode=addlibs", False) + directory(_(33139), "plugin://plugin.video.jellyfin/?mode=updatelibs", False) + directory(_(33140), "plugin://plugin.video.jellyfin/?mode=repairlibs", False) + directory(_(33184), "plugin://plugin.video.jellyfin/?mode=removelibs", False) + directory(_(33060), "plugin://plugin.video.jellyfin/?mode=thememedia", False) xbmcplugin.setContent(int(sys.argv[1]), 'files') xbmcplugin.endOfDirectory(int(sys.argv[1])) @@ -343,16 +343,16 @@ def browse(media, view_id=None, folder=None, server_id=None): 'folder': item['Id'], 'server': server_id } - path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) + path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) context = [] if item['Type'] in ('Series', 'Season', 'Playlist'): - context.append(("Play", "RunPlugin(plugin://plugin.video.emby/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))) + context.append(("Play", "RunPlugin(plugin://plugin.video.jellyfin/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))) if item['UserData']['Played']: - context.append((_(16104), "RunPlugin(plugin://plugin.video.emby/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) + context.append((_(16104), "RunPlugin(plugin://plugin.video.jellyfin/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) else: - context.append((_(16103), "RunPlugin(plugin://plugin.video.emby/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) + context.append((_(16103), "RunPlugin(plugin://plugin.video.jellyfin/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) li.addContextMenuItems(context) list_li.append((path, li, True)) @@ -366,7 +366,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.emby/", urllib.urlencode(params)) + path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) list_li.append((path, li, True)) else: @@ -376,14 +376,14 @@ def browse(media, view_id=None, folder=None, server_id=None): 'mode': "play", 'server': server_id } - path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) + path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) li.setProperty('path', path) - context = [(_(13412), "RunPlugin(plugin://plugin.video.emby/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))] + context = [(_(13412), "RunPlugin(plugin://plugin.video.jellyfin/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))] if item['UserData']['Played']: - context.append((_(16104), "RunPlugin(plugin://plugin.video.emby/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) + context.append((_(16104), "RunPlugin(plugin://plugin.video.jellyfin/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) else: - context.append((_(16103), "RunPlugin(plugin://plugin.video.emby/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) + context.append((_(16103), "RunPlugin(plugin://plugin.video.jellyfin/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) li.addContextMenuItems(context) @@ -419,7 +419,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.emby/", urllib.urlencode(params)) + path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) directory(node[1] or view['Name'], path) xbmcplugin.setContent(int(sys.argv[1]), 'files') @@ -443,7 +443,7 @@ def browse_letters(media, view_id, server_id=None): 'folder': 'firstletter-%s' % node, 'server': server_id } - path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) + path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) directory(node, path) xbmcplugin.setContent(int(sys.argv[1]), 'files') @@ -489,7 +489,7 @@ def get_fanart(item_id, path, server_id=None): ''' Get extra fanart for listitems. This is called by skinhelper. Images are stored locally, due to the Kodi caching system. ''' - if not item_id and 'plugin.video.emby' in path: + if not item_id and 'plugin.video.jellyfin' in path: item_id = path.split('/')[-2] if not item_id: @@ -533,7 +533,7 @@ def get_video_extras(item_id, path, server_id=None): ''' Returns the video files for the item as plugin listing, can be used to browse actual files or video extras, etc. ''' - if not item_id and 'plugin.video.emby' in path: + if not item_id and 'plugin.video.jellyfin' in path: item_id = path.split('/')[-2] if not item_id: @@ -547,7 +547,7 @@ def get_video_extras(item_id, path, server_id=None): #returns the video files for the item as plugin listing, can be used for browsing the actual files or videoextras etc. emby = embyserver.Read_EmbyServer() if not embyId: - if "plugin.video.emby" in embyPath: + if "plugin.video.jellyfin" in embyPath: embyId = embyPath.split("/")[-2] if embyId: item = emby.getItem(embyId) @@ -769,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.emby/library").decode('utf-8') + library = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/library").decode('utf-8') play = settings('useDirectPaths') == "1" if not xbmcvfs.exists(library + '/'): @@ -863,8 +863,8 @@ def backup(): delete_folder(backup) - addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.emby").decode('utf-8') - destination_data = os.path.join(backup, "addon_data", "plugin.video.emby") + addon_data = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin").decode('utf-8') + destination_data = os.path.join(backup, "addon_data", "plugin.video.jellyfin") destination_databases = os.path.join(backup, "Database") if not xbmcvfs.mkdirs(path) or not xbmcvfs.mkdirs(destination_databases): diff --git a/resources/lib/entrypoint/service.py b/resources/lib/entrypoint/service.py index 2fe12f32..0b0392f5 100644 --- a/resources/lib/entrypoint/service.py +++ b/resources/lib/entrypoint/service.py @@ -180,7 +180,8 @@ class Service(xbmc.Monitor): ''' LOG.info("--[ check updates/%s ]", objects.version) kodi = "DEV" if settings('devMode.bool') else xbmc.getInfoLabel('System.BuildVersion') - + # FIXME we do not want their updates + return False try: versions = requests.get('http://kodi.emby.media/Public%20testing/Dependencies/databases.json').json() build = find(versions, kodi) @@ -220,10 +221,10 @@ class Service(xbmc.Monitor): ''' All notifications are sent via NotifyAll built-in or Kodi. Central hub. ''' - if sender.lower() not in ('plugin.video.emby', 'xbmc'): + if sender.lower() not in ('plugin.video.jellyfin', 'xbmc'): return - if sender == 'plugin.video.emby': + if sender == 'plugin.video.jellyfin': method = method.split('.')[1] if method not in ('ServerUnreachable', 'ServerShuttingDown', 'UserDataChanged', 'ServerConnect', diff --git a/resources/lib/helper/playutils.py b/resources/lib/helper/playutils.py index f3146cdc..9814416b 100644 --- a/resources/lib/helper/playutils.py +++ b/resources/lib/helper/playutils.py @@ -503,7 +503,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.emby/temp/").decode('utf-8') + temp = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/").decode('utf-8') if not xbmcvfs.exists(temp): xbmcvfs.mkdir(temp) diff --git a/resources/lib/helper/translate.py b/resources/lib/helper/translate.py index a0731c2d..d6d62248 100644 --- a/resources/lib/helper/translate.py +++ b/resources/lib/helper/translate.py @@ -22,7 +22,7 @@ def _(string): if type(string) != int: string = STRINGS[string] - result = xbmcaddon.Addon('plugin.video.emby').getLocalizedString(string) + result = xbmcaddon.Addon('plugin.video.jellyfin').getLocalizedString(string) if not result: result = xbmc.getLocalizedString(string) diff --git a/resources/lib/helper/utils.py b/resources/lib/helper/utils.py index 71d5bbbb..09e229b4 100644 --- a/resources/lib/helper/utils.py +++ b/resources/lib/helper/utils.py @@ -26,7 +26,7 @@ LOG = logging.getLogger("EMBY."+__name__) ################################################################################################# def addon_id(): - return "plugin.video.emby" + return "plugin.video.jellyfin" def kodi_version(): return xbmc.getInfoLabel('System.BuildVersion')[:2] @@ -134,7 +134,7 @@ def event(method, data=None, sender=None, hexlify=False): ''' Data is a dictionary. ''' data = data or {} - sender = sender or "plugin.video.emby" + sender = sender or "plugin.video.jellyfin" if hexlify: data = '\\"[\\"{0}\\"]\\"'.format(binascii.hexlify(json.dumps(data))) @@ -150,7 +150,7 @@ def dialog(dialog_type, *args, **kwargs): if "icon" in kwargs: kwargs['icon'] = kwargs['icon'].replace("{emby}", - "special://home/addons/plugin.video.emby/icon.png") + "special://home/addons/plugin.video.jellyfin/icon.png") if "heading" in kwargs: kwargs['heading'] = kwargs['heading'].replace("{emby}", _('addon_name')) diff --git a/resources/lib/monitor.py b/resources/lib/monitor.py index d488092b..cbb03f26 100644 --- a/resources/lib/monitor.py +++ b/resources/lib/monitor.py @@ -50,10 +50,10 @@ class Monitor(xbmc.Monitor): def onNotification(self, sender, method, data): - if sender.lower() not in ('plugin.video.emby', 'xbmc', 'upnextprovider.signal'): + if sender.lower() not in ('plugin.video.jellyfin', 'xbmc', 'upnextprovider.signal'): return - if sender == 'plugin.video.emby': + if sender == 'plugin.video.jellyfin': method = method.split('.')[1] if method not in ('GetItem', 'ReportProgressRequested', 'LoadServer', 'RandomItems', 'Recommended', @@ -69,7 +69,7 @@ class Monitor(xbmc.Monitor): elif sender.startswith('upnextprovider'): method = method.split('.')[1] - if method not in ('plugin.video.emby_play_action'): + if method not in ('plugin.video.jellyfin_play_action'): return data = json.loads(data) @@ -312,7 +312,7 @@ class Monitor(xbmc.Monitor): "Mute,Unmute,SetVolume," "Play,Playstate,PlayNext,PlayMediaSource" ), - 'IconUrl': "https://raw.githubusercontent.com/MediaBrowser/plugin.video.emby/develop/kodi_icon.png", + 'IconUrl': "https://raw.githubusercontent.com/MediaBrowser/plugin.video.jellyfin/develop/kodi_icon.png", }) session = server['api'].get_device(self.device_id) diff --git a/resources/lib/objects/actions.py b/resources/lib/objects/actions.py index e2f550cf..b439dbd3 100644 --- a/resources/lib/objects/actions.py +++ b/resources/lib/objects/actions.py @@ -215,7 +215,7 @@ class Actions(object): LOG.info("[ playlist/%s ] %s", item['Id'], item['Name']) self.set_listitem(item, listitem, None, False) - path = "plugin://plugin.video.emby/?mode=play&id=%s&playlist=true" % item['Id'] + path = "plugin://plugin.video.jellyfin/?mode=play&id=%s&playlist=true" % item['Id'] listitem.setPath(path) playlist.add(path, listitem, index) @@ -312,9 +312,9 @@ class Actions(object): obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] or "" if not intro and not obj['Type'] == 'Trailer': - obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby/icon.png" + obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.jellyfin/icon.png" else: - obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or obj['Artwork']['Thumb'] or (obj['Artwork']['Backdrop'][0] if len(obj['Artwork']['Backdrop']) else "special://home/addons/plugin.video.emby/fanart.jpg") + obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or obj['Artwork']['Thumb'] or (obj['Artwork']['Backdrop'][0] if len(obj['Artwork']['Backdrop']) else "special://home/addons/plugin.video.jellyfin/fanart.jpg") obj['Artwork']['Primary'] += "&KodiTrailer=true" if obj['Type'] == 'Trailer' else "&KodiCinemaMode=true" obj['Artwork']['Backdrop'] = [obj['Artwork']['Primary']] @@ -472,9 +472,9 @@ class Actions(object): obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) or 0 obj['Overlay'] = 7 if obj['Played'] else 6 - obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby/icon.png" - obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] or "special://home/addons/plugin.video.emby/fanart.jpg" - obj['Artwork']['Backdrop'] = obj['Artwork']['Backdrop'] or ["special://home/addons/plugin.video.emby/fanart.jpg"] + obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.jellyfin/icon.png" + obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] or "special://home/addons/plugin.video.jellyfin/fanart.jpg" + obj['Artwork']['Backdrop'] = obj['Artwork']['Backdrop'] or ["special://home/addons/plugin.video.jellyfin/fanart.jpg"] metadata = { @@ -657,7 +657,7 @@ class Actions(object): ''' Base resume dialog based on Kodi settings. ''' LOG.info("Resume dialog called.") - XML_PATH = (xbmcaddon.Addon('plugin.video.emby').getAddonInfo('path'), "default", "1080i") + XML_PATH = (xbmcaddon.Addon('plugin.video.jellyfin').getAddonInfo('path'), "default", "1080i") dialog = resume.ResumeDialog("script-emby-resume.xml", *XML_PATH) dialog.set_resume_point("Resume from %s" % str(timedelta(seconds=seektime)).split(".")[0]) diff --git a/resources/lib/objects/movies.py b/resources/lib/objects/movies.py index cf32699c..c49c587c 100644 --- a/resources/lib/objects/movies.py +++ b/resources/lib/objects/movies.py @@ -169,7 +169,7 @@ class Movies(KodiDb): if obj['LocalTrailer']: trailer = self.server['api'].get_local_trailers(obj['Id']) - obj['Trailer'] = "plugin://plugin.video.emby/trailer?id=%s&mode=play" % trailer[0]['Id'] + obj['Trailer'] = "plugin://plugin.video.jellyfin/trailer?id=%s&mode=play" % trailer[0]['Id'] elif obj['Trailer']: obj['Trailer'] = "plugin://plugin.video.youtube/play/?video_id=%s" % obj['Trailer'].rsplit('=', 1)[1] @@ -192,7 +192,7 @@ class Movies(KodiDb): obj['Path'] = obj['Path'].replace(obj['Filename'], "") else: - obj['Path'] = "plugin://plugin.video.emby.movies/" + obj['Path'] = "plugin://plugin.video.jellyfin/" params = { 'filename': obj['Filename'].encode('utf-8'), 'id': obj['Id'], diff --git a/resources/lib/objects/musicvideos.py b/resources/lib/objects/musicvideos.py index 1a528ba4..1dc536e6 100644 --- a/resources/lib/objects/musicvideos.py +++ b/resources/lib/objects/musicvideos.py @@ -174,7 +174,7 @@ class MusicVideos(KodiDb): obj['Path'] = obj['Path'].replace(obj['Filename'], "") else: - obj['Path'] = "plugin://plugin.video.emby.musicvideos/" + obj['Path'] = "plugin://plugin.video.jellyfin/" params = { 'filename': obj['Filename'].encode('utf-8'), 'id': obj['Id'], diff --git a/resources/lib/objects/tvshows.py b/resources/lib/objects/tvshows.py index 5e8c4ec3..d3ab66fb 100644 --- a/resources/lib/objects/tvshows.py +++ b/resources/lib/objects/tvshows.py @@ -217,7 +217,7 @@ class TVShows(KodiDb): if not validate(obj['Path']): raise Exception("Failed to validate path. User stopped.") else: - obj['TopLevel'] = "plugin://plugin.video.emby.tvshows/" + obj['TopLevel'] = "plugin://plugin.video.jellyfin/" obj['Path'] = "%s%s/" % (obj['TopLevel'], obj['Id']) @@ -354,7 +354,7 @@ class TVShows(KodiDb): if not self.direct_path and obj['Resume']: temp_obj = dict(obj) - temp_obj['Path'] = "plugin://plugin.video.emby.tvshows/" + temp_obj['Path'] = "plugin://plugin.video.jellyfin/" temp_obj['PathId'] = self.get_path(*values(temp_obj, QU.get_path_obj)) temp_obj['FileId'] = self.add_file(*values(temp_obj, QU.add_file_obj)) self.update_file(*values(temp_obj, QU.update_file_obj)) @@ -419,7 +419,7 @@ class TVShows(KodiDb): obj['Path'] = obj['Path'].replace(obj['Filename'], "") else: - obj['Path'] = "plugin://plugin.video.emby.tvshows/%s/" % obj['SeriesId'] + obj['Path'] = "plugin://plugin.video.jellyfin/%s/" % obj['SeriesId'] params = { 'filename': obj['Filename'].encode('utf-8'), 'id': obj['Id'], @@ -493,14 +493,14 @@ class TVShows(KodiDb): temp_obj = dict(obj) temp_obj['Filename'] = self.get_filename(*values(temp_obj, QU.get_file_obj)) - temp_obj['Path'] = "plugin://plugin.video.emby.tvshows/" + temp_obj['Path'] = "plugin://plugin.video.jellyfin/" self.remove_file(*values(temp_obj, QU.delete_file_obj)) elif not self.direct_path and obj['Resume']: temp_obj = dict(obj) temp_obj['Filename'] = self.get_filename(*values(temp_obj, QU.get_file_obj)) - temp_obj['PathId'] = self.get_path("plugin://plugin.video.emby.tvshows/") + temp_obj['PathId'] = self.get_path("plugin://plugin.video.jellyfin/") temp_obj['FileId'] = self.add_file(*values(temp_obj, QU.add_file_obj)) self.update_file(*values(temp_obj, QU.update_file_obj)) self.add_playstate(*values(temp_obj, QU.add_bookmark_obj)) diff --git a/resources/lib/player.py b/resources/lib/player.py index 2f522008..277b50d8 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -415,7 +415,7 @@ class Player(xbmc.Player): item['Server']['api'].close_transcode(item['DeviceId']) - path = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/temp/").decode('utf-8') + path = xbmc.translatePath("special://profile/addon_data/plugin.video.jellyfin/temp/").decode('utf-8') if xbmcvfs.exists(path): dirs, files = xbmcvfs.listdir(path) diff --git a/resources/lib/views.py b/resources/lib/views.py index d75b91d6..7b39ea2a 100644 --- a/resources/lib/views.py +++ b/resources/lib/views.py @@ -359,7 +359,7 @@ class Views(object): else: element = etree.Element('node', {'order': str(index), 'type': "folder"}) - etree.SubElement(element, 'icon').text = "special://home/addons/plugin.video.emby/icon.png" + etree.SubElement(element, 'icon').text = "special://home/addons/plugin.video.jellyfin/icon.png" return element @@ -877,7 +877,7 @@ class Views(object): 'mode': "nextepisodes", 'limit': self.limit } - return "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) + return "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) def window_browse(self, view, node=None): @@ -892,7 +892,7 @@ class Views(object): if node: params['folder'] = node - return "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) + return "%s?%s" % ("plugin://plugin.video.jellyfin/", urllib.urlencode(params)) def window_clear(self, name=None): diff --git a/resources/lib/webservice.py b/resources/lib/webservice.py index 9e5f9d33..0561d301 100644 --- a/resources/lib/webservice.py +++ b/resources/lib/webservice.py @@ -126,7 +126,7 @@ class requestHandler(BaseHTTPServer.BaseHTTPRequestHandler): xbmc.log("[ webservice ] path: %s params: %s" % (str(self.path), str(params)), xbmc.LOGWARNING) - path = ("plugin://plugin.video.emby?mode=play&id=%s&dbid=%s&filename=%s&transcode=%s" + path = ("plugin://plugin.video.jellyfin?mode=play&id=%s&dbid=%s&filename=%s&transcode=%s" % (params.get('Id'), params.get('KodiId'), params.get('Name'), params.get('transcode') or False)) self.send_response(200) diff --git a/resources/settings.xml b/resources/settings.xml index 27853e48..3cec88c2 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -5,11 +5,11 @@ - - + + - + @@ -92,19 +92,19 @@ - - + + - + - + - + diff --git a/resources/skins/default/1080i/script-emby-connect-login-manual.xml b/resources/skins/default/1080i/script-emby-connect-login-manual.xml index b2175bc1..d83cb56e 100644 --- a/resources/skins/default/1080i/script-emby-connect-login-manual.xml +++ b/resources/skins/default/1080i/script-emby-connect-login-manual.xml @@ -57,12 +57,12 @@ font13 white 66000000 - + 110 - + ffe1e1e1 66000000 font12 @@ -83,7 +83,7 @@ 110 - + ffe1e1e1 66000000 font12 @@ -103,7 +103,7 @@ - + 426 65 font13 @@ -121,7 +121,7 @@ Conditional - + 426 65 font13 diff --git a/resources/skins/default/1080i/script-emby-connect-login.xml b/resources/skins/default/1080i/script-emby-connect-login.xml index 3b46c85e..7fbb8842 100644 --- a/resources/skins/default/1080i/script-emby-connect-login.xml +++ b/resources/skins/default/1080i/script-emby-connect-login.xml @@ -56,12 +56,12 @@ font13 white 66000000 - + 110 - + ffe1e1e1 66000000 font12 @@ -82,7 +82,7 @@ 110 - + ffe1e1e1 66000000 font12 @@ -102,7 +102,7 @@ - + 426 65 font13 @@ -119,7 +119,7 @@ Conditional - + 426 65 font13 @@ -141,7 +141,7 @@ - + font_flag ff464646 66000000 @@ -165,7 +165,7 @@ 135 center - + font_flag true FF52b54b diff --git a/resources/skins/default/1080i/script-emby-connect-server-manual.xml b/resources/skins/default/1080i/script-emby-connect-server-manual.xml index 7aa3f37a..7a436d61 100644 --- a/resources/skins/default/1080i/script-emby-connect-server-manual.xml +++ b/resources/skins/default/1080i/script-emby-connect-server-manual.xml @@ -57,12 +57,12 @@ font13 white 66000000 - + 110 - + ffe1e1e1 66000000 font12 @@ -83,7 +83,7 @@ 110 - + ffe1e1e1 66000000 font12 @@ -103,7 +103,7 @@ - + 426 65 font13 @@ -120,7 +120,7 @@ Conditional - + 426 65 font13 diff --git a/resources/skins/default/1080i/script-emby-connect-server.xml b/resources/skins/default/1080i/script-emby-connect-server.xml index 37bf63e0..c20c535d 100644 --- a/resources/skins/default/1080i/script-emby-connect-server.xml +++ b/resources/skins/default/1080i/script-emby-connect-server.xml @@ -64,7 +64,7 @@ font13 white 66000000 - + 200 @@ -161,7 +161,7 @@ 20 - + 476 65 font13 @@ -179,7 +179,7 @@ Conditional - + 476 65 font13 @@ -197,7 +197,7 @@ Conditional - + 476 65 font13 diff --git a/resources/skins/default/1080i/script-emby-connect-users.xml b/resources/skins/default/1080i/script-emby-connect-users.xml index 9547d718..dfb2ce91 100644 --- a/resources/skins/default/1080i/script-emby-connect-users.xml +++ b/resources/skins/default/1080i/script-emby-connect-users.xml @@ -57,7 +57,7 @@ font13 white 66000000 - + Conditional @@ -175,7 +175,7 @@ - + 874 65 font13 @@ -193,7 +193,7 @@ Conditional - + 874 65 font13 diff --git a/service.py b/service.py index 3292a122..64dfc595 100644 --- a/service.py +++ b/service.py @@ -13,7 +13,7 @@ import xbmcaddon ################################################################################################# -__addon__ = xbmcaddon.Addon(id='plugin.video.emby') +__addon__ = xbmcaddon.Addon(id='plugin.video.jellyfin') __base__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'resources', 'lib')).decode('utf-8') __libraries__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('path'), 'libraries')).decode('utf-8') __pcache__ = xbmc.translatePath(os.path.join(__addon__.getAddonInfo('profile'), 'emby')).decode('utf-8')