mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2025-05-07 18:08:50 +00:00
New hybrid method
This commit is contained in:
parent
7f5084c62e
commit
ace50b34dc
279 changed files with 39526 additions and 19994 deletions
26
resources/lib/entrypoint/__init__.py
Normal file
26
resources/lib/entrypoint/__init__.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from helper import loghandler
|
||||
from emby import Emby
|
||||
|
||||
#################################################################################################
|
||||
|
||||
Emby.set_loghandler(loghandler.LogHandler, logging.DEBUG)
|
||||
loghandler.config()
|
||||
LOG = logging.getLogger('EMBY.entrypoint')
|
||||
|
||||
#################################################################################################
|
||||
|
||||
try:
|
||||
sys.path.insert(0, xbmc.translatePath('special://temp/emby/').decode('utf-8'))
|
||||
except Exception as error:
|
||||
LOG.debug('No objects not found, using default.')
|
||||
|
||||
from default import Events
|
||||
from service import Service
|
||||
from context import Context
|
159
resources/lib/entrypoint/context.py
Normal file
159
resources/lib/entrypoint/context.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
|
||||
import database
|
||||
from dialogs import context
|
||||
from helper import _, settings, dialog
|
||||
from downloader import TheVoid
|
||||
from objects import Actions
|
||||
|
||||
#################################################################################################
|
||||
|
||||
LOG = logging.getLogger("EMBY."+__name__)
|
||||
XML_PATH = (xbmcaddon.Addon('plugin.video.emby').getAddonInfo('path'), "default", "1080i")
|
||||
OPTIONS = {
|
||||
'Refresh': _(30410),
|
||||
'Delete': _(30409),
|
||||
'Addon': _(30408),
|
||||
'AddFav': _(30405),
|
||||
'RemoveFav': _(30406),
|
||||
'Transcode': _(30412)
|
||||
}
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
class Context(object):
|
||||
|
||||
_selected_option = None
|
||||
|
||||
def __init__(self, transcode=False):
|
||||
|
||||
self.kodi_id = sys.listitem.getVideoInfoTag().getDbId() or None
|
||||
self.media = self.get_media_type()
|
||||
self.server = sys.listitem.getProperty('embyserver') or None
|
||||
item_id = sys.listitem.getProperty('embyid')
|
||||
|
||||
if self.server or item_id:
|
||||
self.item = TheVoid('GetItem', {'ServerId': self.server, 'Id': item_id}).get()
|
||||
else:
|
||||
self.item = self.get_item_id()
|
||||
|
||||
if self.item:
|
||||
|
||||
if transcode:
|
||||
self.transcode()
|
||||
|
||||
elif self.select_menu():
|
||||
self.action_menu()
|
||||
|
||||
if self._selected_option.decode('utf-8') in (OPTIONS['Delete'], OPTIONS['AddFav'], OPTIONS['RemoveFav']):
|
||||
|
||||
xbmc.sleep(500)
|
||||
xbmc.executebuiltin('Container.Refresh')
|
||||
|
||||
def get_media_type(self):
|
||||
|
||||
''' Get media type based on sys.listitem. If unfilled, base on visible window.
|
||||
'''
|
||||
media = sys.listitem.getVideoInfoTag().getMediaType()
|
||||
|
||||
if not media:
|
||||
|
||||
if xbmc.getCondVisibility('Container.Content(albums)'):
|
||||
media = "album"
|
||||
elif xbmc.getCondVisibility('Container.Content(artists)'):
|
||||
media = "artist"
|
||||
elif xbmc.getCondVisibility('Container.Content(songs)'):
|
||||
media = "song"
|
||||
elif xbmc.getCondVisibility('Container.Content(pictures)'):
|
||||
media = "picture"
|
||||
else:
|
||||
LOG.info("media is unknown")
|
||||
|
||||
return media.decode('utf-8')
|
||||
|
||||
def get_item_id(self):
|
||||
|
||||
''' Get synced item from embydb.
|
||||
'''
|
||||
item = database.get_item(self.kodi_id, self.media)
|
||||
|
||||
if not item:
|
||||
return
|
||||
|
||||
return {
|
||||
'Id': item[0],
|
||||
'UserData': json.loads(item[4]) if item[4] else {},
|
||||
'Type': item[3]
|
||||
}
|
||||
|
||||
def select_menu(self):
|
||||
|
||||
''' Display the select dialog.
|
||||
Favorites, Refresh, Delete (opt), Settings.
|
||||
'''
|
||||
options = []
|
||||
|
||||
if self.item['Type'] not in ('Season'):
|
||||
|
||||
if self.item['UserData'].get('IsFavorite'):
|
||||
options.append(OPTIONS['RemoveFav'])
|
||||
else:
|
||||
options.append(OPTIONS['AddFav'])
|
||||
|
||||
options.append(OPTIONS['Refresh'])
|
||||
|
||||
if settings('enableContextDelete.bool'):
|
||||
options.append(OPTIONS['Delete'])
|
||||
|
||||
options.append(OPTIONS['Addon'])
|
||||
|
||||
context_menu = context.ContextMenu("script-emby-context.xml", *XML_PATH)
|
||||
context_menu.set_options(options)
|
||||
context_menu.doModal()
|
||||
|
||||
if context_menu.is_selected():
|
||||
self._selected_option = context_menu.get_selected()
|
||||
|
||||
return self._selected_option
|
||||
|
||||
def action_menu(self):
|
||||
|
||||
selected = self._selected_option.decode('utf-8')
|
||||
|
||||
if selected == OPTIONS['Refresh']:
|
||||
TheVoid('RefreshItem', {'ServerId': self.server, 'Id': self.item['Id']})
|
||||
|
||||
elif selected == OPTIONS['AddFav']:
|
||||
TheVoid('FavoriteItem', {'ServerId': self.server, 'Id': self.item['Id'], 'Favorite': True})
|
||||
|
||||
elif selected == OPTIONS['RemoveFav']:
|
||||
TheVoid('FavoriteItem', {'ServerId': self.server, 'Id': self.item['Id'], 'Favorite': False})
|
||||
|
||||
elif selected == OPTIONS['Addon']:
|
||||
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
|
||||
|
||||
elif selected == OPTIONS['Delete']:
|
||||
delete = True
|
||||
|
||||
if not settings('skipContextMenu.bool'):
|
||||
|
||||
if not dialog("yesno", heading="{emby}", line1=_(33015)):
|
||||
delete = False
|
||||
|
||||
if delete:
|
||||
TheVoid('DeleteItem', {'ServerId': self.server, 'Id': self.item['Id']})
|
||||
|
||||
def transcode(self):
|
||||
|
||||
item = TheVoid('GetItem', {'Id': self.item['Id'], 'ServerId': self.server}).get()
|
||||
Actions(self.server).play(item, self.kodi_id, True)
|
667
resources/lib/entrypoint/default.py
Normal file
667
resources/lib/entrypoint/default.py
Normal file
|
@ -0,0 +1,667 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import urlparse
|
||||
import urllib
|
||||
import os
|
||||
import sys
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
|
||||
import client
|
||||
from database import reset, get_sync, Database, emby_db, get_credentials
|
||||
from objects import Objects, Actions
|
||||
from downloader import TheVoid
|
||||
from helper import _, event, settings, window, dialog, api, JSONRPC
|
||||
from emby import Emby
|
||||
|
||||
#################################################################################################
|
||||
|
||||
LOG = logging.getLogger("EMBY."+__name__)
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
class Events(object):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
''' Parse the parameters. Reroute to our service.py
|
||||
where user is fully identified already.
|
||||
'''
|
||||
base_url = sys.argv[0]
|
||||
path = sys.argv[2]
|
||||
|
||||
try:
|
||||
params = dict(urlparse.parse_qsl(path[1:]))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
mode = params.get('mode')
|
||||
server = params.get('server')
|
||||
|
||||
if server == 'None':
|
||||
server = None
|
||||
|
||||
LOG.warn("path: %s params: %s", path, json.dumps(params, indent=4))
|
||||
|
||||
if '/extrafanart' in base_url:
|
||||
|
||||
emby_path = path[1:]
|
||||
emby_id = params.get('id')
|
||||
get_fanart(emby_id, emby_path, server)
|
||||
|
||||
elif '/Extras' in base_url or '/VideoFiles' in base_url:
|
||||
|
||||
emby_path = path[1:]
|
||||
emby_id = params.get('id')
|
||||
get_video_extras(emby_id, emby_path, server)
|
||||
|
||||
elif mode =='play':
|
||||
|
||||
item = TheVoid('GetItem', {'Id': params['id'], 'ServerId': server}).get()
|
||||
Actions(params.get('server')).play(item, params.get('dbid'))
|
||||
|
||||
elif mode == 'playlist':
|
||||
event('PlayPlaylist', {'Id': params['id'], 'ServerId': server})
|
||||
elif mode == 'deviceid':
|
||||
client.reset_device_id()
|
||||
elif mode == 'reset':
|
||||
reset()
|
||||
elif mode == 'refreshboxsets':
|
||||
event('SyncLibrary', {'Id': "Boxsets:Refresh"})
|
||||
elif mode == 'nextepisodes':
|
||||
get_next_episodes(params['id'], params['limit'])
|
||||
elif mode == 'browse':
|
||||
browse(params.get('type'), params.get('id'), params.get('folder'), server)
|
||||
elif mode == 'synclib':
|
||||
event('SyncLibrary', {'Id': params.get('id')})
|
||||
elif mode == 'repairlib':
|
||||
event('RepairLibrary', {'Id': params.get('id')})
|
||||
elif mode == 'removelib':
|
||||
event('RemoveLibrary', {'Id': params.get('id')})
|
||||
elif mode == 'repairlibs':
|
||||
event('RepairLibrarySelection')
|
||||
elif mode == 'updatelibs':
|
||||
event('SyncLibrarySelection')
|
||||
elif mode == 'connect':
|
||||
event('EmbyConnect')
|
||||
elif mode == 'addserver':
|
||||
event('AddServer')
|
||||
elif mode == 'login':
|
||||
event('ServerConnect', {'Id': server})
|
||||
elif mode == 'removeserver':
|
||||
event('RemoveServer', {'Id': server})
|
||||
elif mode == 'settings':
|
||||
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
|
||||
elif mode == 'adduser':
|
||||
add_user()
|
||||
elif mode == 'updateserver':
|
||||
event('UpdateServer')
|
||||
elif mode == 'thememedia':
|
||||
get_themes()
|
||||
else:
|
||||
listing()
|
||||
|
||||
|
||||
def listing():
|
||||
|
||||
''' Display all emby nodes and dynamic entries when appropriate.
|
||||
'''
|
||||
total = int(window('Emby.nodes.total') or 0)
|
||||
sync = get_sync()
|
||||
servers = get_credentials()['Servers'][1:]
|
||||
|
||||
for i in range(total):
|
||||
|
||||
window_prop = "Emby.nodes.%s" % i
|
||||
path = window('%s.index' % window_prop)
|
||||
|
||||
if not path:
|
||||
path = window('%s.content' % window_prop) or window('%s.path' % window_prop)
|
||||
|
||||
label = window('%s.title' % window_prop)
|
||||
node = window('%s.type' % window_prop)
|
||||
artwork = window('%s.artwork' % window_prop)
|
||||
view_id = window('%s.id' % window_prop)
|
||||
context = []
|
||||
|
||||
if view_id and node in ('movies', 'tvshows', 'musicvideos', 'music') and view_id not in sync['Whitelist']:
|
||||
|
||||
context.append((_(33123), "RunPlugin(plugin://plugin.video.emby?mode=synclib&id=%s)" % view_id))
|
||||
|
||||
if view_id and node in ('movies', 'tvshows', 'musicvideos', 'music') and view_id in sync['Whitelist']:
|
||||
|
||||
context.append((_(33136), "RunPlugin(plugin://plugin.video.emby?mode=synclib&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))
|
||||
|
||||
LOG.debug("--[ listing/%s/%s ] %s", node, label, path)
|
||||
|
||||
if path:
|
||||
if xbmc.getCondVisibility('Window.IsActive(Pictures)') and node in ('photos', 'homevideos'):
|
||||
directory(label, path, artwork=artwork)
|
||||
elif xbmc.getCondVisibility('Window.IsActive(Videos)') and node not in ('photos', 'homevideos', 'music'):
|
||||
directory(label, path, artwork=artwork, context=context)
|
||||
elif xbmc.getCondVisibility('Window.IsActive(Music)') and node == 'music':
|
||||
directory(label, path, artwork=artwork, context=context)
|
||||
elif not xbmc.getCondVisibility('Window.IsActive(Videos) | Window.IsActive(Pictures) | Window.IsActive(Music)'):
|
||||
directory(label, path, artwork=artwork)
|
||||
|
||||
for server in servers:
|
||||
context = []
|
||||
|
||||
if server.get('ManualAddress'):
|
||||
context.append((_(33141), "RunPlugin(plugin://plugin.video.emby/?mode=removeserver&server=%s)"))
|
||||
|
||||
if 'AccessToken' not in server:
|
||||
directory("%s (%s)" % (server['Name'], _(30539)), "plugin://plugin.video.emby/?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(_(33134), "plugin://plugin.video.emby/?mode=addserver", False)
|
||||
directory(_(5), "plugin://plugin.video.emby/?mode=settings", False)
|
||||
directory(_(33054), "plugin://plugin.video.emby/?mode=adduser", False)
|
||||
directory(_(33098), "plugin://plugin.video.emby/?mode=refreshboxsets", False)
|
||||
directory(_(33139), "plugin://plugin.video.emby/?mode=updatelibs", False)
|
||||
directory(_(33140), "plugin://plugin.video.emby/?mode=repairlibs", False)
|
||||
directory(_(33060), "plugin://plugin.video.emby/?mode=thememedia", False)
|
||||
directory(_(33058), "plugin://plugin.video.emby/?mode=reset", False)
|
||||
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
def directory(label, path, folder=True, artwork=None, fanart=None, context=None):
|
||||
|
||||
''' Add directory listitem. context should be a list of tuples [(label, action)*]
|
||||
'''
|
||||
li = dir_listitem(label, path, artwork, fanart)
|
||||
|
||||
if context:
|
||||
li.addContextMenuItems(context)
|
||||
|
||||
xbmcplugin.addDirectoryItem(int(sys.argv[1]), path, li, folder)
|
||||
|
||||
return li
|
||||
|
||||
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"})
|
||||
|
||||
return li
|
||||
|
||||
def browse(media, view_id=None, folder=None, server_id=None):
|
||||
|
||||
''' Browse content dynamically.
|
||||
'''
|
||||
LOG.info("--[ v:%s/%s ] %s", view_id, media, folder)
|
||||
|
||||
if view_id:
|
||||
|
||||
view = TheVoid('GetItem', {'ServerId': server_id, 'Id': view_id}).get()
|
||||
xbmcplugin.setPluginCategory(int(sys.argv[1]), view['Name'])
|
||||
|
||||
content_type = "files"
|
||||
|
||||
if media in ('tvshows', 'seasons', 'episodes', 'movies', 'musicvideos'):
|
||||
content_type = media
|
||||
elif media in ('homevideos', 'photos'):
|
||||
content_type = "images"
|
||||
|
||||
if folder == 'FavEpisodes':
|
||||
listing = TheVoid('Browse', {'Media': "Episode", 'ServerId': server_id, 'Limit': 25, 'Filters': "IsFavorite"}).get()
|
||||
elif media == 'homevideos':
|
||||
listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': "Video,Folder,PhotoAlbum,Photo", 'ServerId': server_id, 'Recursive': False}).get()
|
||||
elif media == 'movies':
|
||||
listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': "Movie,BoxSet", 'ServerId': server_id, 'Recursive': True}).get()
|
||||
elif media == 'episodes':
|
||||
listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': "Episode", 'ServerId': server_id, 'Recursive': True}).get()
|
||||
elif media == 'library':
|
||||
listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': True}).get()
|
||||
else:
|
||||
listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': False}).get()
|
||||
|
||||
|
||||
if listing and listing.get('Items'):
|
||||
|
||||
actions = Actions(server_id)
|
||||
list_li = []
|
||||
|
||||
for item in listing['Items']:
|
||||
|
||||
li = xbmcgui.ListItem()
|
||||
li.setProperty('embyid', item['Id'])
|
||||
li.setProperty('embyserver', server_id)
|
||||
actions.set_listitem(item, li)
|
||||
|
||||
if item.get('IsFolder'):
|
||||
|
||||
params = {
|
||||
'id': view_id or item['Id'],
|
||||
'mode': "browse",
|
||||
'type': get_folder_type(item) or media,
|
||||
'folder': item['Id'],
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.emby", 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)))
|
||||
|
||||
if item['UserData']['Played']:
|
||||
context.append((_(16104), "RunPlugin(plugin://plugin.video.emby?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)))
|
||||
|
||||
li.addContextMenuItems(context)
|
||||
list_li.append((path, li, True))
|
||||
else:
|
||||
if item['Type'] not in ('Photo', 'PhotoAlbum'):
|
||||
params = {
|
||||
'id': item['Id'],
|
||||
'mode': "play",
|
||||
'server': server_id
|
||||
}
|
||||
path = "%s?%s" % ("plugin://plugin.video.emby", urllib.urlencode(params))
|
||||
li.setProperty('path', path)
|
||||
context = [(_(13412), "RunPlugin(plugin://plugin.video.emby?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)))
|
||||
else:
|
||||
context.append((_(16103), "RunPlugin(plugin://plugin.video.emby?mode=watched&id=%s&server=%s)" % (item['Id'], server_id)))
|
||||
|
||||
li.addContextMenuItems(context)
|
||||
|
||||
list_li.append((li.getProperty('path'), li, False))
|
||||
|
||||
xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li))
|
||||
|
||||
if content_type == 'images':
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE)
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RATING)
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
|
||||
|
||||
xbmcplugin.setContent(int(sys.argv[1]), content_type)
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
def get_folder_type(item):
|
||||
|
||||
media = item['Type']
|
||||
|
||||
if media == 'Series':
|
||||
return "seasons"
|
||||
elif media == 'Season':
|
||||
return "episodes"
|
||||
elif media == 'BoxSet':
|
||||
return "movies"
|
||||
elif media == 'MusicArtist':
|
||||
return "albums"
|
||||
elif media == 'MusicAlbum':
|
||||
return "songs"
|
||||
elif media == 'CollectionFolder':
|
||||
return item.get('CollectionType', 'library')
|
||||
|
||||
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:
|
||||
item_id = path.split('/')[-2]
|
||||
|
||||
if not item_id:
|
||||
return
|
||||
|
||||
LOG.info("[ extra fanart ] %s", item_id)
|
||||
objects = Objects()
|
||||
list_li = []
|
||||
API = api.API(item, TheVoid('GetServerAddress', {'ServerId': server_id}).get())
|
||||
directory = xbmc.translatePath("special://thumbnails/emby/%s/" % item_id).decode('utf-8')
|
||||
|
||||
if not xbmcvfs.exists(directory):
|
||||
|
||||
xbmcvfs.mkdirs(directory)
|
||||
item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get()
|
||||
obj = objects.map(item, 'Artwork')
|
||||
backdrops = API.get_all_artwork(obj)
|
||||
tags = obj['BackdropTags']
|
||||
|
||||
for index, backdrop in enumerate(backdrops):
|
||||
|
||||
tag = tags[index]
|
||||
fanart = os.path.join(directory, "fanart%s.jpg" % tag)
|
||||
li = xbmcgui.ListItem(tag, path=fanart)
|
||||
xbmcvfs.copy(backdrop, fanart)
|
||||
list_li.append((fanart, li, False))
|
||||
else:
|
||||
LOG.debug("cached backdrop found")
|
||||
dirs, files = xbmcvfs.listdir(directory)
|
||||
|
||||
for file in files:
|
||||
fanart = os.path.join(directory, file.decode('utf-8'))
|
||||
li = xbmcgui.ListItem(file, path=fanart)
|
||||
list_li.append((fanart, li, False))
|
||||
|
||||
xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li))
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
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:
|
||||
item_id = path.split('/')[-2]
|
||||
|
||||
if not item_id:
|
||||
return
|
||||
|
||||
item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get()
|
||||
# TODO
|
||||
|
||||
"""
|
||||
def getVideoFiles(embyId,embyPath):
|
||||
#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:
|
||||
embyId = embyPath.split("/")[-2]
|
||||
if embyId:
|
||||
item = emby.getItem(embyId)
|
||||
putils = playutils.PlayUtils(item)
|
||||
if putils.isDirectPlay():
|
||||
#only proceed if we can access the files directly. TODO: copy local on the fly if accessed outside
|
||||
filelocation = putils.directPlay()
|
||||
if not filelocation.endswith("/"):
|
||||
filelocation = filelocation.rpartition("/")[0]
|
||||
dirs, files = xbmcvfs.listdir(filelocation)
|
||||
for file in files:
|
||||
file = filelocation + file
|
||||
li = xbmcgui.ListItem(file, path=file)
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=file, listitem=li)
|
||||
for dir in dirs:
|
||||
dir = filelocation + dir
|
||||
li = xbmcgui.ListItem(dir, path=dir)
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=dir, listitem=li, isFolder=True)
|
||||
#xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
"""
|
||||
|
||||
def get_next_episodes(item_id, limit):
|
||||
|
||||
''' Only for synced content.
|
||||
'''
|
||||
with Database('emby') as embydb:
|
||||
|
||||
db = emby_db.EmbyDatabase(embydb.cursor)
|
||||
library = db.get_view_name(item_id)
|
||||
|
||||
if not library:
|
||||
return
|
||||
|
||||
result = JSONRPC('VideoLibrary.GetTVShows').execute({
|
||||
'sort': {'order': "descending", 'method': "lastplayed"},
|
||||
'filter': {
|
||||
'and': [
|
||||
{'operator': "true", 'field': "inprogress", 'value': ""},
|
||||
{'operator': "is", 'field': "tag", 'value': "%s" % library}
|
||||
]},
|
||||
'properties': ['title', 'studio', 'mpaa', 'file', 'art']
|
||||
})
|
||||
|
||||
try:
|
||||
items = result['result']['tvshows']
|
||||
except (KeyError, TypeError):
|
||||
return
|
||||
|
||||
list_li = []
|
||||
|
||||
for item in items:
|
||||
if settings('ignoreSpecialsNextEpisodes.bool'):
|
||||
params = {
|
||||
'tvshowid': item['tvshowid'],
|
||||
'sort': {'method': "episode"},
|
||||
'filter': {
|
||||
'and': [
|
||||
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
||||
{'operator': "greaterthan", 'field': "season", 'value': "0"}
|
||||
]},
|
||||
'properties': [
|
||||
"title", "playcount", "season", "episode", "showtitle",
|
||||
"plot", "file", "rating", "resume", "tvshowid", "art",
|
||||
"streamdetails", "firstaired", "runtime", "writer",
|
||||
"dateadded", "lastplayed"
|
||||
],
|
||||
'limits': {"end": 1}
|
||||
}
|
||||
else:
|
||||
params = {
|
||||
'tvshowid': item['tvshowid'],
|
||||
'sort': {'method': "episode"},
|
||||
'filter': {'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
||||
'properties': [
|
||||
"title", "playcount", "season", "episode", "showtitle",
|
||||
"plot", "file", "rating", "resume", "tvshowid", "art",
|
||||
"streamdetails", "firstaired", "runtime", "writer",
|
||||
"dateadded", "lastplayed"
|
||||
],
|
||||
'limits': {"end": 1}
|
||||
}
|
||||
|
||||
result = JSONRPC('VideoLibrary.GetEpisodes').execute(params)
|
||||
|
||||
try:
|
||||
episodes = result['result']['episodes']
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
else:
|
||||
for episode in episodes:
|
||||
|
||||
li = create_listitem(episode)
|
||||
list_li.append((episode['file'], li))
|
||||
|
||||
if len(list_li) == limit:
|
||||
break
|
||||
|
||||
xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li))
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
def create_listitem(item):
|
||||
|
||||
''' Listitem based on jsonrpc items.
|
||||
'''
|
||||
title = item['title']
|
||||
label2 = ""
|
||||
li = xbmcgui.ListItem(title)
|
||||
li.setProperty('IsPlayable', "true")
|
||||
|
||||
metadata = {
|
||||
'Title': title,
|
||||
'duration': str(item['runtime']/60),
|
||||
'Plot': item['plot'],
|
||||
'Playcount': item['playcount']
|
||||
}
|
||||
|
||||
if "showtitle" in item:
|
||||
metadata['TVshowTitle'] = item['showtitle']
|
||||
label2 = item['showtitle']
|
||||
|
||||
if "episodeid" in item:
|
||||
# Listitem of episode
|
||||
metadata['mediatype'] = "episode"
|
||||
metadata['dbid'] = item['episodeid']
|
||||
|
||||
# TODO: Review once Krypton is RC - probably no longer needed if there's dbid
|
||||
if "episode" in item:
|
||||
episode = item['episode']
|
||||
metadata['Episode'] = episode
|
||||
|
||||
if "season" in item:
|
||||
season = item['season']
|
||||
metadata['Season'] = season
|
||||
|
||||
if season and episode:
|
||||
episodeno = "s%.2de%.2d" % (season, episode)
|
||||
li.setProperty('episodeno', episodeno)
|
||||
label2 = "%s - %s" % (label2, episodeno) if label2 else episodeno
|
||||
|
||||
if "firstaired" in item:
|
||||
metadata['Premiered'] = item['firstaired']
|
||||
|
||||
if "rating" in item:
|
||||
metadata['Rating'] = str(round(float(item['rating']),1))
|
||||
|
||||
if "director" in item:
|
||||
metadata['Director'] = " / ".join(item['director'])
|
||||
|
||||
if "writer" in item:
|
||||
metadata['Writer'] = " / ".join(item['writer'])
|
||||
|
||||
if "cast" in item:
|
||||
cast = []
|
||||
castandrole = []
|
||||
for person in item['cast']:
|
||||
name = person['name']
|
||||
cast.append(name)
|
||||
castandrole.append((name, person['role']))
|
||||
metadata['Cast'] = cast
|
||||
metadata['CastAndRole'] = castandrole
|
||||
|
||||
li.setLabel2(label2)
|
||||
li.setInfo(type="Video", infoLabels=metadata)
|
||||
li.setProperty('resumetime', str(item['resume']['position']))
|
||||
li.setProperty('totaltime', str(item['resume']['total']))
|
||||
li.setArt(item['art'])
|
||||
li.setThumbnailImage(item['art'].get('thumb',''))
|
||||
li.setIconImage('DefaultTVShows.png')
|
||||
li.setProperty('dbid', str(item['episodeid']))
|
||||
li.setProperty('fanart_image', item['art'].get('tvshow.fanart',''))
|
||||
|
||||
for key, value in item['streamdetails'].iteritems():
|
||||
for stream in value:
|
||||
li.addStreamInfo(key, stream)
|
||||
|
||||
return li
|
||||
|
||||
def add_user():
|
||||
|
||||
''' Add or remove users from the default server session.
|
||||
'''
|
||||
if not window('emby_online.bool'):
|
||||
return
|
||||
|
||||
session = TheVoid('GetSession', {}).get()
|
||||
users = TheVoid('GetUsers', {'IsDisabled': False, 'IsHidden': False}).get()
|
||||
current = session[0]['AdditionalUsers']
|
||||
|
||||
result = dialog("select", _(33061), [_(33062), _(33063)] if current else [_(33062)])
|
||||
|
||||
if result < 0:
|
||||
return
|
||||
|
||||
if not result: # Add user
|
||||
eligible = [x for x in users if x['Id'] not in [current_user['UserId'] for current_user in current]]
|
||||
resp = dialog("select", _(33064), [x['Name'] for x in eligible])
|
||||
|
||||
if resp < 0:
|
||||
return
|
||||
|
||||
user = eligible[resp]
|
||||
event('AddUser', {'Id': user['Id'], 'Add': True})
|
||||
else: # Remove user
|
||||
resp = dialog("select", _(33064), [x['UserName'] for x in current])
|
||||
|
||||
if resp < 0:
|
||||
return
|
||||
|
||||
user = current[resp]
|
||||
event('AddUser', {'Id': user['UserId'], 'Add': False})
|
||||
|
||||
def get_themes():
|
||||
|
||||
''' Add theme media locally, via strm. This is only for tv tunes.
|
||||
If another script is used, adjust this code.
|
||||
'''
|
||||
from helper.utils import normalize_string
|
||||
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')
|
||||
play = settings('useDirectPaths') == "1"
|
||||
|
||||
if not xbmcvfs.exists(library):
|
||||
xbmcvfs.mkdir(library)
|
||||
|
||||
if xbmc.getCondVisibility('System.HasAddon(script.tvtunes)'):
|
||||
|
||||
tvtunes = xbmcaddon.Addon(id="script.tvtunes")
|
||||
tvtunes.setSetting('custom_path_enable', "true")
|
||||
tvtunes.setSetting('custom_path', library)
|
||||
LOG.info("TV Tunes custom path is enabled and set.")
|
||||
else:
|
||||
dialog("ok", heading="{emby}", line1=_(33152))
|
||||
|
||||
return
|
||||
|
||||
with Database('emby') as embydb:
|
||||
all_views = emby_db.EmbyDatabase(embydb.cursor).get_views()
|
||||
views = [x[0] for x in all_views if x[2] in ('movies', 'tvshows', 'mixed')]
|
||||
|
||||
|
||||
items = {}
|
||||
server = TheVoid('GetServerAddress', {'ServerId': None}).get()
|
||||
token = TheVoid('GetToken', {'ServerId': None}).get()
|
||||
|
||||
for view in views:
|
||||
result = TheVoid('GetThemes', {'Type': "Video", 'Id': view}).get()
|
||||
|
||||
for item in result['Items']:
|
||||
|
||||
folder = normalize_string(item['Name'].encode('utf-8'))
|
||||
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'))
|
||||
items[item['Id']] = folder
|
||||
|
||||
for item in items:
|
||||
|
||||
nfo_path = os.path.join(library, items[item])
|
||||
nfo_file = os.path.join(nfo_path, "tvtunes.nfo")
|
||||
|
||||
if not xbmcvfs.exists(nfo_path):
|
||||
xbmcvfs.mkdir(nfo_path)
|
||||
|
||||
themes = TheVoid('GetTheme', {'Id': item}).get()
|
||||
paths = []
|
||||
|
||||
for theme in themes['ThemeVideosResult']['Items'] + themes['ThemeSongsResult']['Items']:
|
||||
putils = PlayUtils(theme, False, None, server, token)
|
||||
|
||||
if play:
|
||||
paths.append(putils.direct_play(theme['MediaSources'][0]).encode('utf-8'))
|
||||
else:
|
||||
paths.append(putils.direct_url(theme['MediaSources'][0]).encode('utf-8'))
|
||||
|
||||
tvtunes_nfo(nfo_file, paths)
|
||||
|
||||
dialog("notification", heading="{emby}", message=_(33153), icon="{emby}", time=1000, sound=False)
|
461
resources/lib/entrypoint/service.py
Normal file
461
resources/lib/entrypoint/service.py
Normal file
|
@ -0,0 +1,461 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import _strptime # Workaround for threads using datetime: _striptime is locked
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
import connect
|
||||
import client
|
||||
import library
|
||||
import setup
|
||||
import monitor
|
||||
import objects.utils
|
||||
from libraries import requests
|
||||
from views import Views, verify_kodi_defaults
|
||||
from helper import _, window, settings, event, dialog, find
|
||||
from objects import version
|
||||
from downloader import get_objects
|
||||
from emby import Emby
|
||||
|
||||
#################################################################################################
|
||||
|
||||
LOG = logging.getLogger("EMBY."+__name__)
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
class Service(xbmc.Monitor):
|
||||
|
||||
running = True
|
||||
library_thread = None
|
||||
monitor = None
|
||||
play_event = None
|
||||
warn = True
|
||||
settings = {'last_progress': datetime.today()}
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.settings['profile'] = xbmc.translatePath('special://profile')
|
||||
self.settings['mode'] = settings('useDirectPaths')
|
||||
self.settings['log_level'] = settings('logLevel') or "1"
|
||||
self.settings['enable_context'] = settings('enableContext.bool')
|
||||
self.settings['enable_context_transcode'] = settings('enableContextTranscode.bool')
|
||||
self.settings['kodi_companion'] = settings('kodiCompanion.bool')
|
||||
window('emby_logLevel', value=str(self.settings['log_level']))
|
||||
window('emby_kodiProfile', value=self.settings['profile'])
|
||||
|
||||
if self.settings['enable_context']:
|
||||
window('emby_context', value="true")
|
||||
if self.settings['enable_context_transcode']:
|
||||
window('emby_context_transcode', value="true")
|
||||
|
||||
LOG.warn("--->>>[ %s ]", client.get_addon_name())
|
||||
LOG.warn("Version: %s", client.get_version())
|
||||
LOG.warn("KODI Version: %s", xbmc.getInfoLabel('System.BuildVersion'))
|
||||
LOG.warn("Platform: %s", client.get_platform())
|
||||
LOG.warn("Python Version: %s", sys.version)
|
||||
LOG.warn("Using dynamic paths: %s", settings('useDirectPaths') == "0")
|
||||
LOG.warn("Log Level: %s", self.settings['log_level'])
|
||||
|
||||
verify_kodi_defaults()
|
||||
Views().get_nodes()
|
||||
window('emby.connected.bool', True)
|
||||
|
||||
xbmc.Monitor.__init__(self)
|
||||
self.check_update()
|
||||
settings('groupedSets.bool', objects.utils.get_grouped_set())
|
||||
|
||||
def service(self):
|
||||
|
||||
''' Keeps the service monitor going.
|
||||
Exit on Kodi shutdown or profile switch.
|
||||
|
||||
if profile switch happens more than once,
|
||||
Threads depending on abortRequest will not trigger.
|
||||
'''
|
||||
self.monitor = monitor.Monitor()
|
||||
self.connect = connect.Connect()
|
||||
self.start_default()
|
||||
|
||||
self.settings['mode'] = settings('useDirectPaths')
|
||||
|
||||
while self.running:
|
||||
if window('emby_online.bool'):
|
||||
|
||||
if self.settings['profile'] != window('emby_kodiProfile'):
|
||||
LOG.info("[ profile switch ] %s", self.settings['profile'])
|
||||
|
||||
break
|
||||
|
||||
if self.monitor.player.isPlaying():
|
||||
difference = datetime.today() - self.settings['last_progress']
|
||||
|
||||
if difference.seconds > 270:
|
||||
|
||||
event("ReportProgressRequested", None)
|
||||
self.settings['last_progress'] = datetime.today()
|
||||
|
||||
if self.waitForAbort(1):
|
||||
break
|
||||
|
||||
self.shutdown()
|
||||
|
||||
def start_default(self):
|
||||
|
||||
try:
|
||||
self.connect.register()
|
||||
setup.Setup()
|
||||
except Exception as error:
|
||||
LOG.error(error)
|
||||
|
||||
def stop_default(self):
|
||||
|
||||
window('emby_online', clear=True)
|
||||
Emby().close()
|
||||
|
||||
if self.library_thread is not None:
|
||||
|
||||
self.library_thread.stop_client()
|
||||
self.library_thread = None
|
||||
|
||||
|
||||
def check_update(self):
|
||||
|
||||
''' Check for objects build version and compare.
|
||||
This pulls a dict that contains all the information for the build needed.
|
||||
'''
|
||||
LOG.info("--[ check updates ]")
|
||||
kodi = xbmc.getInfoLabel('System.BuildVersion')
|
||||
url = "https://sheets.googleapis.com/v4/spreadsheets/1cKWQCVL0lVONulO2KyGzBilzhGvsyuSjFvrqe8g6nJw/values/A2:B?key=AIzaSyAP-1mcBglk9zIofJlqGpvKXkff3GRMhdI"
|
||||
|
||||
try:
|
||||
self.versions = {k.lower(): v for k, v in dict(requests.get(url).json()['values']).items()}
|
||||
build = find(self.versions, kodi)
|
||||
|
||||
if not build:
|
||||
raise Exception("build %s incompatible?!", kodi)
|
||||
|
||||
label, zipfile = build.split('-', 1)
|
||||
|
||||
if label == version:
|
||||
LOG.info("--[ objects/%s ]", version)
|
||||
|
||||
return
|
||||
|
||||
get_objects(zipfile, label + '.zip')
|
||||
except Exception as error:
|
||||
|
||||
LOG.info(error)
|
||||
self.shutdown()
|
||||
|
||||
return
|
||||
|
||||
dialog("ok", heading="{emby}", line1=_(33135))
|
||||
xbmc.executebuiltin('RestartApp')
|
||||
|
||||
def onNotification(self, sender, method, data):
|
||||
|
||||
''' All notifications are sent via NotifyAll built-in or Kodi.
|
||||
Central hub.
|
||||
'''
|
||||
if sender.lower() not in ('plugin.video.emby', 'xbmc'):
|
||||
return
|
||||
|
||||
if sender == 'plugin.video.emby':
|
||||
method = method.split('.')[1]
|
||||
|
||||
if method not in ('ServerUnreachable', 'ServerShuttingDown', 'UserDataChanged', 'ServerConnect',
|
||||
'LibraryChanged', 'ServerOnline', 'SyncLibrary', 'RepairLibrary', 'RemoveLibrary',
|
||||
'EmbyConnect', 'SyncLibrarySelection', 'RepairLibrarySelection', 'AddServer',
|
||||
'Unauthorized', 'UpdateServer', 'UserConfigurationUpdated', 'ServerRestarting'):
|
||||
return
|
||||
|
||||
data = json.loads(data)[0]
|
||||
else:
|
||||
if method not in ('System.OnQuit', 'System.OnSleep', 'System.OnWake'):
|
||||
return
|
||||
|
||||
data = json.loads(data)
|
||||
|
||||
LOG.debug("[ %s: %s ] %s", sender, method, json.dumps(data, indent=4))
|
||||
|
||||
if method == 'ServerOnline':
|
||||
if data['ServerId'] is None:
|
||||
|
||||
window('emby_online.bool', True)
|
||||
self.warn = True
|
||||
|
||||
if self.library_thread is None:
|
||||
|
||||
self.library_thread = library.Library(self)
|
||||
self.library_thread.start()
|
||||
|
||||
elif method in ('ServerUnreachable', 'ServerShuttingDown'):
|
||||
|
||||
if self.warn or data.get('ServerId'):
|
||||
|
||||
self.warn = data.get('ServerId') is not None
|
||||
dialog("notification", heading="{emby}", message=_(33146) if data.get('ServerId') is None else _(33149), icon=xbmcgui.NOTIFICATION_ERROR)
|
||||
|
||||
if data.get('ServerId') is None:
|
||||
self.stop_default()
|
||||
|
||||
if self.waitForAbort(20):
|
||||
return
|
||||
|
||||
self.start_default()
|
||||
|
||||
elif method == 'Unauthorized':
|
||||
dialog("notification", heading="{emby}", message=_(33147) if data['ServerId'] is None else _(33148), icon=xbmcgui.NOTIFICATION_ERROR)
|
||||
|
||||
elif method == 'ServerRestarting':
|
||||
if data.get('ServerId'):
|
||||
return
|
||||
|
||||
if settings('restartMsg.bool'):
|
||||
dialog("notification", heading="{emby}", message=_(33006), icon="{emby}")
|
||||
|
||||
self.stop_default()
|
||||
|
||||
if self.waitForAbort(10):
|
||||
return
|
||||
|
||||
self.start_default()
|
||||
|
||||
elif method == 'ServerConnect':
|
||||
self.connect.register(data['Id'])
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'EmbyConnect':
|
||||
self.connect.setup_login_connect()
|
||||
|
||||
elif method == 'AddServer':
|
||||
|
||||
self.connect.setup_manual_server()
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'RemoveServer':
|
||||
|
||||
self.connect.remove_server(data['Id'])
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'UpdateServer':
|
||||
|
||||
dialog("ok", heading="{emby}", line1=_(33151))
|
||||
self.connect.setup_manual_server()
|
||||
|
||||
elif method == 'UserDataChanged' and self.library_thread:
|
||||
if data.get('ServerId'):
|
||||
return
|
||||
|
||||
self.library_thread.userdata(data['UserDataList'])
|
||||
|
||||
elif method == 'LibraryChanged' and self.library_thread:
|
||||
if data.get('ServerId'):
|
||||
return
|
||||
|
||||
self.library_thread.updated(data['ItemsUpdated'] + data['ItemsAdded'])
|
||||
self.library_thread.removed(data['ItemsRemoved'])
|
||||
|
||||
elif method == 'System.OnQuit':
|
||||
window('emby_should_stop.bool', True)
|
||||
self.running = False
|
||||
|
||||
elif method in ('SyncLibrarySelection', 'RepairLibrarySelection'):
|
||||
self.library_thread.select_libraries('SyncLibrary' if method == 'SyncLibrarySelection' else 'RepairLibrary')
|
||||
|
||||
elif method == 'SyncLibrary':
|
||||
libraries = data['Id'].split(',')
|
||||
|
||||
for lib in libraries:
|
||||
self.library_thread.add_library(lib)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'RepairLibrary':
|
||||
libraries = data['Id'].split(',')
|
||||
|
||||
for lib in libraries:
|
||||
self.library_thread.remove_library(lib)
|
||||
self.library_thread.add_library(lib)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'RemoveLibrary':
|
||||
libraries = data['Id'].split(',')
|
||||
|
||||
for lib in libraries:
|
||||
self.library_thread.remove_library(lib)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif method == 'System.OnSleep':
|
||||
LOG.info("-->[ sleep ]")
|
||||
|
||||
if self.library_thread is not None:
|
||||
|
||||
self.library_thread.stop_client()
|
||||
self.library_thread = None
|
||||
|
||||
Emby.close_all()
|
||||
|
||||
elif method == 'System.OnWake':
|
||||
|
||||
LOG.info("--<[ sleep ]")
|
||||
xbmc.sleep(10000)# Allow network to wake up
|
||||
|
||||
try:
|
||||
self.connect.register()
|
||||
except Exception as error:
|
||||
LOG.error(error)
|
||||
|
||||
elif method == 'GUI.OnScreensaverDeactivated':
|
||||
|
||||
LOG.info("--<[ screensaver ]")
|
||||
xbmc.sleep(5000)
|
||||
|
||||
if self.library_thread is not None:
|
||||
self.library_thread.fast_sync()
|
||||
|
||||
elif method == 'UserConfigurationUpdated':
|
||||
|
||||
if data.get('ServerId') is None:
|
||||
Views().get_views()
|
||||
|
||||
def onSettingsChanged(self):
|
||||
|
||||
''' React to setting changes that impact window values.
|
||||
'''
|
||||
if window('emby_should_stop.bool'):
|
||||
return
|
||||
|
||||
if settings('logLevel') != self.settings['log_level']:
|
||||
|
||||
log_level = settings('logLevel')
|
||||
window('emby_logLevel', str(log_level))
|
||||
self.settings['logLevel'] = log_level
|
||||
LOG.warn("New log level: %s", log_level)
|
||||
|
||||
if settings('enableContext.bool') != self.settings['enable_context']:
|
||||
|
||||
window('emby_context', settings('enableContext'))
|
||||
self.settings['enable_context'] = settings('enableContext.bool')
|
||||
LOG.warn("New context setting: %s", self.settings['enable_context'])
|
||||
|
||||
if settings('enableContextTranscode.bool') != self.settings['enable_context_transcode']:
|
||||
|
||||
window('emby_context_transcode', settings('enableContextTranscode'))
|
||||
self.settings['enable_context_transcode'] = settings('enableContextTranscode.bool')
|
||||
LOG.warn("New context transcode setting: %s", self.settings['enable_context_transcode'])
|
||||
|
||||
if settings('useDirectPaths') != self.settings['mode'] and self.library_thread.started:
|
||||
|
||||
self.settings['mode'] = settings('useDirectPaths')
|
||||
LOG.warn("New playback mode setting: %s", self.settings['mode'])
|
||||
|
||||
if not self.settings.get('mode_warn'):
|
||||
|
||||
self.settings['mode_warn'] = True
|
||||
dialog("yesno", heading="{emby}", line1=_(33118))
|
||||
|
||||
if settings('kodiCompanion.bool') != self.settings['kodi_companion']:
|
||||
self.settings['kodi_companion'] = settings('kodiCompanion.bool')
|
||||
|
||||
if not self.settings['kodi_companion']:
|
||||
dialog("ok", heading="{emby}", line1=_(33138))
|
||||
|
||||
def shutdown(self):
|
||||
|
||||
LOG.warn("---<[ EXITING ]")
|
||||
|
||||
properties = [ # TODO: review
|
||||
"emby_state", "emby_serverStatus",
|
||||
"emby_syncRunning", "emby_dbCheck",
|
||||
"emby_currUser", "emby_dbScan",
|
||||
"emby_initialScan", "emby_playbackProps",
|
||||
|
||||
"emby_play", "emby_online", "emby.connected", "emby_should_stop", "emby.resume",
|
||||
"emby.external", "emby.external_check"
|
||||
]
|
||||
for prop in properties:
|
||||
window(prop, clear=True)
|
||||
|
||||
Emby.close_all()
|
||||
|
||||
if self.library_thread is not None:
|
||||
self.library_thread.stop_client()
|
||||
|
||||
if self.monitor is not None:
|
||||
self.monitor.listener.stop()
|
||||
|
||||
LOG.warn("---<<<[ %s ]", client.get_addon_name())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
if window('emby_online') == "true":
|
||||
|
||||
# Emby server is online
|
||||
# Verify if user is set and has access to the server
|
||||
if user_client.get_user() is not None and user_client.get_access():
|
||||
|
||||
if self.kodi_player.isPlaying():
|
||||
self._report_progress()
|
||||
|
||||
# If an item is playing
|
||||
if not self.startup:
|
||||
self.startup = self._startup()
|
||||
|
||||
if not self.websocket_running:
|
||||
# Start the Websocket Client
|
||||
self.websocket_running = True
|
||||
self.websocket_thread.start()
|
||||
if not self.library_running:
|
||||
# Start the syncing thread
|
||||
self.library_running = True
|
||||
self.library_thread.start()
|
||||
if not self.capabitilities and user_client.post_capabilities():
|
||||
self.capabitilities = True
|
||||
|
||||
if self.monitor.waitForAbort(15):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
else:
|
||||
|
||||
if (user_client.get_user() is None) and self.warn_auth:
|
||||
# Alert user is not authenticated and suppress future warning
|
||||
self.warn_auth = False
|
||||
log.info("Not authenticated yet.")
|
||||
|
||||
# User access is restricted.
|
||||
# Keep verifying until access is granted
|
||||
# unless server goes offline or Kodi is shut down.
|
||||
self._access_check()
|
||||
else:
|
||||
# Wait until Emby server is online
|
||||
# or Kodi is shut down.
|
||||
self._server_online_check()
|
||||
|
||||
if self.monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
"""
|
Loading…
Add table
Add a link
Reference in a new issue