This commit is contained in:
angelblue05 2016-09-08 22:13:25 -05:00 committed by GitHub
parent e941674e74
commit b945459dfb
8 changed files with 447 additions and 419 deletions

View File

@ -5,171 +5,204 @@
import logging
import os
import sys
import urlparse
import xbmc
import xbmcaddon
import xbmcgui
#################################################################################################
_addon = xbmcaddon.Addon(id='plugin.video.emby')
_addon_path = _addon.getAddonInfo('path').decode('utf-8')
_base_resource = xbmc.translatePath(os.path.join(_addon_path, 'resources', 'lib')).decode('utf-8')
sys.path.append(_base_resource)
_ADDON = xbmcaddon.Addon(id='plugin.video.emby')
_CWD = _ADDON.getAddonInfo('path').decode('utf-8')
_BASE_LIB = xbmc.translatePath(os.path.join(_CWD, 'resources', 'lib')).decode('utf-8')
sys.path.append(_BASE_LIB)
#################################################################################################
import api
import artwork
import downloadutils
import librarysync
import loghandler
import read_embyserver as embyserver
import embydb_functions as embydb
import kodidb_functions as kodidb
import musicutils as musicutils
from utils import settings, language as lang, kodiSQL
from utils import settings, dialog, language as lang, kodiSQL
#################################################################################################
import loghandler
loghandler.config()
log = logging.getLogger("EMBY.contextmenu")
#################################################################################################
OPTIONS = {
'Refresh': lang(30410),
'Delete': lang(30409),
'Addon': lang(30408),
'AddFav': lang(30405),
'RemoveFav': lang(30406),
'RateSong': lang(30407)
}
class ContextMenu(object):
_selected_option = None
def __init__(self):
self.emby = embyserver.Read_EmbyServer()
self.kodi_id = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
self.item_type = self._get_item_type()
self.item_id = self._get_item_id(self.kodi_id, self.item_type)
log.info("Found item_id: %s item_type: %s", self.item_id, self.item_type)
if self.item_id:
self.item = self.emby.getItem(self.item_id)
self.api = api.API(self.item)
if self._select_menu():
self._action_menu()
xbmc.sleep(500)
xbmc.executebuiltin('Container.Refresh')
@classmethod
def _get_item_type(cls):
item_type = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
if not item_type:
if xbmc.getCondVisibility('Container.Content(albums)'):
item_type = "album"
elif xbmc.getCondVisibility('Container.Content(artists)'):
item_type = "artist"
elif xbmc.getCondVisibility('Container.Content(songs)'):
item_type = "song"
elif xbmc.getCondVisibility('Container.Content(pictures)'):
item_type = "picture"
else:
log.info("item_type is unknown")
return item_type
@classmethod
def _get_item_id(cls, kodi_id, item_type):
item_id = xbmc.getInfoLabel('ListItem.Property(embyid)')
if not item_id and kodi_id and item_type:
conn = kodiSQL('emby')
cursor = conn.cursor()
emby_db = embydb.Embydb_Functions(cursor)
item = emby_db.getItem_byKodiId(kodi_id, item_type)
cursor.close()
try:
item_id = item[0]
except TypeError:
pass
return item_id
def _select_menu(self):
# Display select dialog
userdata = self.api.getUserData()
options = []
if userdata['Favorite']:
# Remove from emby favourites
options.append(OPTIONS['RemoveFav'])
else:
# Add to emby favourites
options.append(OPTIONS['AddFav'])
if self.item_type == "song":
# Set custom song rating
options.append(OPTIONS['RateSong'])
# Refresh item
options.append(OPTIONS['Refresh'])
# Delete item
options.append(OPTIONS['Delete'])
# Addon settings
options.append(OPTIONS['Addon'])
resp = dialog(type_="select", heading=lang(30401), list=options)
if resp > -1:
self._selected_option = options[resp]
return self._selected_option
def _action_menu(self):
selected = self._selected_option
if selected == OPTIONS['Refresh']:
self.emby.refreshItem(self.item_id)
elif selected == OPTIONS['AddFav']:
self.emby.updateUserRating(self.item_id, favourite=True)
elif selected == OPTIONS['RemoveFav']:
self.emby.updateUserRating(self.item_id, favourite=False)
elif selected == OPTIONS['RateSong']:
self._rate_song()
elif selected == OPTIONS['Addon']:
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
elif selected == OPTIONS['Delete']:
self._delete_item()
def _rate_song(self):
conn = kodiSQL('music')
cursor = conn.cursor()
query = "SELECT rating FROM song WHERE idSong = ?"
cursor.execute(query, (self.kodi_id,))
try:
value = cursor.fetchone()[0]
current_value = int(round(float(value), 0))
except TypeError:
pass
else:
new_value = dialog("numeric", 0, lang(30411), str(current_value))
if new_value > -1:
new_value = int(new_value)
if new_value > 5:
new_value = 5
if settings('enableUpdateSongRating') == "true":
musicutils.updateRatingToFile(new_value, self.api.getFilePath())
query = "UPDATE song SET rating = ? WHERE idSong = ?"
cursor.execute(query, (new_value, self.kodi_id,))
conn.commit()
finally:
cursor.close()
def _delete_item(self):
delete = True
if settings('skipContextMenu') != "true":
if not dialog(type_="yesno", heading="{emby}", line1=lang(33041)):
log.info("User skipped deletion for: %s", self.item_id)
delete = False
if delete:
log.info("Deleting request: %s", self.item_id)
self.emby.deleteItem(self.item_id)
# Kodi contextmenu item to configure the emby settings
if __name__ == '__main__':
kodiId = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
itemType = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
itemId = ""
if not itemType:
if xbmc.getCondVisibility("Container.Content(albums)"):
itemType = "album"
elif xbmc.getCondVisibility("Container.Content(artists)"):
itemType = "artist"
elif xbmc.getCondVisibility("Container.Content(songs)"):
itemType = "song"
elif xbmc.getCondVisibility("Container.Content(pictures)"):
itemType = "picture"
else:
log.info("ItemType is unknown.")
if (not kodiId or kodiId == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"):
itemId = xbmc.getInfoLabel("ListItem.Property(embyid)")
elif kodiId and itemType:
embyconn = kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(kodiId, itemType)
embycursor.close()
try:
itemId = item[0]
except TypeError:
pass
log.info("Found ItemId: %s ItemType: %s" % (itemId, itemType))
if itemId:
dialog = xbmcgui.Dialog()
emby = embyserver.Read_EmbyServer()
item = emby.getItem(itemId)
API = api.API(item)
userdata = API.getUserData()
likes = userdata['Likes']
favourite = userdata['Favorite']
options = []
if favourite:
# Remove from emby favourites
options.append(lang(30406))
else:
# Add to emby favourites
options.append(lang(30405))
if itemType == "song":
# Set custom song rating
options.append(lang(30407))
# Refresh item
options.append(lang(30410))
# Delete item
options.append(lang(30409))
# Addon settings
options.append(lang(30408))
# Display select dialog and process results
resp = xbmcgui.Dialog().select(lang(30401), options)
if resp > -1:
selected = options[resp]
if selected == lang(30410):
# Refresh item
emby.refreshItem(itemId)
elif selected == lang(30405):
# Add favourite
emby.updateUserRating(itemId, favourite=True)
elif selected == lang(30406):
# Delete favourite
emby.updateUserRating(itemId, favourite=False)
elif selected == lang(30407):
# Update song rating
kodiconn = kodiSQL('music')
kodicursor = kodiconn.cursor()
query = "SELECT rating FROM song WHERE idSong = ?"
kodicursor.execute(query, (kodiId,))
try:
value = kodicursor.fetchone()[0]
current_value = int(round(float(value),0))
except TypeError:
pass
else:
new_value = dialog.numeric(0, lang(30411), str(current_value))
if new_value > -1:
new_value = int(new_value)
if new_value > 5:
new_value = 5
if settings('enableUpdateSongRating') == "true":
musicutils.updateRatingToFile(new_value, API.getFilePath())
query = "UPDATE song SET rating = ? WHERE idSong = ?"
kodicursor.execute(query, (new_value, kodiId,))
kodiconn.commit()
'''if settings('enableExportSongRating') == "true":
like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(new_value)
emby.updateUserRating(itemId, like, favourite, deletelike)'''
finally:
kodicursor.close()
elif selected == lang(30408):
# Open addon settings
xbmc.executebuiltin("Addon.OpenSettings(plugin.video.emby)")
elif selected == lang(30409):
# delete item from the server
delete = True
if settings('skipContextMenu') != "true":
resp = dialog.yesno(
heading=lang(29999),
line1=lang(33041))
if not resp:
log.info("User skipped deletion for: %s." % itemId)
delete = False
if delete:
log.info("Deleting request: %s" % itemId)
emby.deleteItem(itemId)
xbmc.sleep(500)
xbmc.executebuiltin('Container.Refresh')
log.info("plugin.video.emby contextmenu started")
ContextMenu()
log.info("plugin.video.emby contextmenu stopped")

View File

@ -9,52 +9,74 @@ import urlparse
import xbmc
import xbmcaddon
import xbmcgui
#################################################################################################
_addon = xbmcaddon.Addon(id='plugin.video.emby')
_addon_path = _addon.getAddonInfo('path').decode('utf-8')
_base_resource = xbmc.translatePath(os.path.join(_addon_path, 'resources', 'lib')).decode('utf-8')
sys.path.append(_base_resource)
_ADDON = xbmcaddon.Addon(id='plugin.video.emby')
_CWD = _ADDON.getAddonInfo('path').decode('utf-8')
_BASE_LIB = xbmc.translatePath(os.path.join(_CWD, 'resources', 'lib')).decode('utf-8')
sys.path.append(_BASE_LIB)
#################################################################################################
import entrypoint
import utils
from utils import window, language as lang
import loghandler
from utils import window, dialog, language as lang
#################################################################################################
import loghandler
loghandler.config()
log = logging.getLogger("EMBY.default")
#################################################################################################
class Main():
class Main(object):
# MAIN ENTRY POINT
#@utils.profiling()
def __init__(self):
# Parse parameters
base_url = sys.argv[0]
params = urlparse.parse_qs(sys.argv[2][1:])
log.warn("Parameter string: %s" % sys.argv[2])
path = sys.argv[2]
params = urlparse.parse_qs(path[1:])
log.warn("Parameter string: %s", path)
try:
mode = params['mode'][0]
itemid = params.get('id')
if itemid:
itemid = itemid[0]
except:
params = {}
except (IndexError, KeyError):
mode = ""
if "/extrafanart" in base_url:
emby_path = path[1:]
emby_id = params.get('id', [""])[0]
entrypoint.getExtraFanArt(emby_id, emby_path)
elif "/Extras" in base_url or "/VideoFiles" in base_url:
emby_path = path[1:]
emby_id = params.get('id', [""])[0]
entrypoint.getVideoFiles(emby_id, emby_path)
elif not self._modes(mode, params):
# Other functions
if mode == 'settings':
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
elif mode in ('manualsync', 'fastsync', 'repair'):
self._library_sync(mode)
elif mode == 'texturecache':
import artwork
artwork.Artwork().fullTextureCacheSync()
else:
entrypoint.doMainListing()
@classmethod
def _modes(cls, mode, params):
import utils
modes = {
'reset': utils.reset,
@ -75,76 +97,63 @@ class Main():
'delete': entrypoint.deleteItem,
'connect': entrypoint.emby_connect
}
if "/extrafanart" in sys.argv[0]:
embypath = sys.argv[2][1:]
embyid = params.get('id',[""])[0]
entrypoint.getExtraFanArt(embyid,embypath)
return
if "/Extras" in sys.argv[0] or "/VideoFiles" in sys.argv[0]:
embypath = sys.argv[2][1:]
embyid = params.get('id',[""])[0]
entrypoint.getVideoFiles(embyid, embypath)
return
if modes.get(mode):
if mode in modes:
# Simple functions
if mode == "play":
dbid = params.get('dbid')
modes[mode](itemid, dbid)
action = modes[mode]
item_id = params.get('id')
if item_id:
item_id = item_id[0]
elif mode in ("nextup", "inprogressepisodes", "recentepisodes"):
if mode == 'play':
database_id = params.get('dbid')
action(item_id, database_id)
elif mode in ('nextup', 'inprogressepisodes', 'recentepisodes'):
limit = int(params['limit'][0])
modes[mode](itemid, limit)
elif mode in ("channels","getsubfolders"):
modes[mode](itemid)
elif mode == "browsecontent":
modes[mode](itemid, params.get('type',[""])[0], params.get('folderid',[""])[0])
action(item_id, limit)
elif mode == "channelsfolder":
elif mode in ('channels', 'getsubfolders'):
action(item_id)
elif mode == 'browsecontent':
action(item_id, params.get('type', [""])[0], params.get('folderid', [""])[0])
elif mode == 'channelsfolder':
folderid = params['folderid'][0]
modes[mode](itemid, folderid)
action(item_id, folderid)
else:
modes[mode]()
else:
# Other functions
if mode == "settings":
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
elif mode in ("manualsync", "fastsync", "repair"):
if window('emby_online') != "true":
# Server is not online, do not run the sync
xbmcgui.Dialog().ok(heading=lang(29999),
line1=lang(33034))
log.warn("Not connected to the emby server.")
return
if window('emby_dbScan') != "true":
import librarysync
lib = librarysync.LibrarySync()
if mode == "manualsync":
librarysync.ManualSync().sync()
elif mode == "fastsync":
lib.startSync()
else:
lib.fullSync(repair=True)
else:
log.warn("Database scan is already running.")
elif mode == "texturecache":
import artwork
artwork.Artwork().fullTextureCacheSync()
else:
entrypoint.doMainListing()
action()
return True
return False
@classmethod
def _library_sync(cls, mode):
if window('emby_online') != "true":
# Server is not online, do not run the sync
dialog(type_="ok",
heading="{emby}",
line1=lang(33034))
log.warn("Not connected to the emby server.")
elif window('emby_dbScan') != "true":
import librarysync
library_sync = librarysync.LibrarySync()
if mode == 'manualsync':
librarysync.ManualSync().sync()
elif mode == 'fastsync':
library_sync.startSync()
else:
library_sync.fullSync(repair=True)
else:
log.warn("Database scan is already running.")
if __name__ == "__main__":
log.info('plugin.video.emby started')
log.info("plugin.video.emby started")
Main()
log.info('plugin.video.emby stopped')
log.info("plugin.video.emby stopped")

View File

@ -98,9 +98,9 @@ class PlaybackUtils():
dummyPlaylist = True
playlist.add(playurl, listitem, index=startPos)
# Remove the original item from playlist
self.pl.removefromPlaylist(startPos+1)
self.pl.remove_from_playlist(startPos+1)
# Readd the original item to playlist - via jsonrpc so we have full metadata
self.pl.insertintoPlaylist(currentPosition+1, dbid, self.item['Type'].lower())
self.pl.insert_to_playlist(currentPosition+1, dbid, self.item['Type'].lower())
currentPosition += 1
############### -- CHECK FOR INTROS ################
@ -131,7 +131,7 @@ class PlaybackUtils():
pbutils = PlaybackUtils(intro)
pbutils.setProperties(introPlayurl, introListItem)
self.pl.insertintoPlaylist(currentPosition, url=introPlayurl)
self.pl.insert_to_playlist(currentPosition, url=introPlayurl)
introsPlaylist = True
currentPosition += 1
@ -142,7 +142,7 @@ class PlaybackUtils():
# Extend our current playlist with the actual item to play
# only if there's no playlist first
log.info("Adding main item to playlist.")
self.pl.addtoPlaylist(dbid, self.item['Type'].lower())
self.pl.add_to_playlist(dbid, self.item['Type'].lower())
# Ensure that additional parts are played after the main item
currentPosition += 1
@ -166,7 +166,7 @@ class PlaybackUtils():
pbutils.setArtwork(additionalListItem)
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition)
self.pl.verifyPlaylist()
self.pl.verify_playlist()
currentPosition += 1
if dummyPlaylist:
@ -181,7 +181,7 @@ class PlaybackUtils():
log.debug("Resetting properties playback flag.")
window('emby_playbackProps', clear=True)
#self.pl.verifyPlaylist()
#self.pl.verify_playlist()
########## SETUP MAIN ITEM ##########
# For transcoding only, ask for audio/subs pref

View File

@ -38,7 +38,7 @@ class Player(xbmc.Player):
self.clientInfo = clientinfo.ClientInfo()
self.doUtils = downloadutils.DownloadUtils().downloadUrl
self.ws = wsc.WebSocket_Client()
self.ws = wsc.WebSocketClient()
self.xbmcplayer = xbmc.Player()
log.debug("Starting playback monitor.")

View File

@ -2,18 +2,16 @@
#################################################################################################
import json
import logging
import xbmc
import xbmcgui
import xbmcplugin
import playutils
import playbackutils
import embydb_functions as embydb
import read_embyserver as embyserver
from utils import window, settings, language as lang, kodiSQL
from utils import window, kodiSQL, JSONRPC
#################################################################################################
@ -22,169 +20,141 @@ log = logging.getLogger("EMBY."+__name__)
#################################################################################################
class Playlist():
class Playlist(object):
def __init__(self):
self.userid = window('emby_currUser')
self.server = window('emby_server%s' % self.userid)
self.emby = embyserver.Read_EmbyServer()
def playAll(self, itemids, startat):
def play_all(self, item_ids, start_at):
embyconn = kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
conn = kodiSQL('emby')
cursor = conn.cursor()
emby_db = embydb.Embydb_Functions(cursor)
player = xbmc.Player()
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
playlist.clear()
log.info("---*** PLAY ALL ***---")
log.info("Items: %s and start at: %s" % (itemids, startat))
log.info("Items: %s and start at: %s", item_ids, start_at)
started = False
window('emby_customplaylist', value="true")
if startat != 0:
if start_at:
# Seek to the starting position
window('emby_customplaylist.seektime', str(startat))
window('emby_customplaylist.seektime', str(start_at))
for itemid in itemids:
embydb_item = emby_db.getItem_byId(itemid)
for item_id in item_ids:
log.info("Adding %s to playlist", item_id)
item = emby_db.getItem_byId(item_id)
try:
dbid = embydb_item[0]
mediatype = embydb_item[4]
db_id = item[0]
media_type = item[4]
except TypeError:
# Item is not found in our database, add item manually
log.info("Item was not found in the database, manually adding item.")
item = self.emby.getItem(itemid)
self.addtoPlaylist_xbmc(playlist, item)
else:
# Add to playlist
self.addtoPlaylist(dbid, mediatype)
log.info("Item was not found in the database, manually adding item")
item = self.emby.getItem(item_id)
self.add_to_xbmc_playlist(playlist, item)
log.info("Adding %s to playlist." % itemid)
else: # Add to playlist
self.add_to_playlist(db_id, media_type)
if not started:
started = True
player.play(playlist)
self.verifyPlaylist()
embycursor.close()
self.verify_playlist()
cursor.close()
def modifyPlaylist(self, itemids):
def modify_playlist(self, item_ids):
embyconn = kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
conn = kodiSQL('emby')
cursor = conn.cursor()
emby_db = embydb.Embydb_Functions(cursor)
log.info("---*** ADD TO PLAYLIST ***---")
log.info("Items: %s" % itemids)
log.info("Items: %s", item_ids)
player = xbmc.Player()
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
for itemid in itemids:
embydb_item = emby_db.getItem_byId(itemid)
for item_id in item_ids:
log.info("Adding %s to playlist", item_id)
item = emby_db.getItem_byId(item_id)
try:
dbid = embydb_item[0]
mediatype = embydb_item[4]
db_id = item[0]
media_type = item[4]
except TypeError:
# Item is not found in our database, add item manually
item = self.emby.getItem(itemid)
self.addtoPlaylist_xbmc(playlist, item)
else:
# Add to playlist
self.addtoPlaylist(dbid, mediatype)
item = self.emby.getItem(item_id)
self.add_to_xbmc_playlist(playlist, item)
log.info("Adding %s to playlist." % itemid)
else: # Add to playlist
self.add_to_playlist(db_id, media_type)
self.verifyPlaylist()
embycursor.close()
self.verify_playlist()
cursor.close()
return playlist
def addtoPlaylist(self, dbid=None, mediatype=None, url=None):
pl = {
'jsonrpc': "2.0",
'id': 1,
'method': "Playlist.Add",
'params': {
'playlistid': 1
}
}
if dbid is not None:
pl['params']['item'] = {'%sid' % mediatype: int(dbid)}
else:
pl['params']['item'] = {'file': url}
log.debug(xbmc.executeJSONRPC(json.dumps(pl)))
def addtoPlaylist_xbmc(self, playlist, item):
@classmethod
def add_to_xbmc_playlist(cls, playlist, item):
playurl = playutils.PlayUtils(item).getPlayUrl()
if not playurl:
# Playurl failed
log.info("Failed to retrieve playurl.")
log.info("Failed to retrieve playurl")
return
log.info("Playurl: %s" % playurl)
log.info("Playurl: %s", playurl)
listitem = xbmcgui.ListItem()
playbackutils.PlaybackUtils(item).setProperties(playurl, listitem)
playlist.add(playurl, listitem)
def insertintoPlaylist(self, position, dbid=None, mediatype=None, url=None):
@classmethod
def add_to_playlist(cls, db_id=None, media_type=None, url=None):
pl = {
params = {
'jsonrpc': "2.0",
'id': 1,
'method': "Playlist.Insert",
'params': {
'playlistid': 1,
'position': position
}
'playlistid': 1
}
if dbid is not None:
pl['params']['item'] = {'%sid' % mediatype: int(dbid)}
if db_id is not None:
params['item'] = {'%sid' % media_type: int(db_id)}
else:
pl['params']['item'] = {'file': url}
params['item'] = {'file': url}
log.debug(xbmc.executeJSONRPC(json.dumps(pl)))
log.debug(JSONRPC('Playlist.Add').execute(params))
def verifyPlaylist(self):
@classmethod
def insert_to_playlist(cls, position, db_id=None, media_type=None, url=None):
pl = {
params = {
'jsonrpc': "2.0",
'id': 1,
'method': "Playlist.GetItems",
'params': {
'playlistid': 1
}
'playlistid': 1,
'position': position
}
log.debug(xbmc.executeJSONRPC(json.dumps(pl)))
if db_id is not None:
params['item'] = {'%sid' % media_type: int(db_id)}
else:
params['item'] = {'file': url}
def removefromPlaylist(self, position):
log.debug(JSONRPC('Playlist.Insert').execute(params))
pl = {
@classmethod
def verify_playlist(cls):
log.debug(JSONRPC('Playlist.GetItems').execute({'playlistid': 1}))
'jsonrpc': "2.0",
'id': 1,
'method': "Playlist.Remove",
'params': {
@classmethod
def remove_from_playlist(cls, position):
'playlistid': 1,
'position': position
}
params = {
'playlistid': 1,
'position': position
}
log.debug(xbmc.executeJSONRPC(json.dumps(pl)))
log.debug(JSONRPC('Playlist.Remove').execute(params))

View File

@ -57,12 +57,16 @@ def dialog(type_, **kwargs):
if "icon" in kwargs:
kwargs['icon'] = kwargs['icon'].replace("{emby}",
"special://home/addons/plugin.video.emby/icon.png")
if "heading" in kwargs:
kwargs['heading'] = kwargs['heading'].replace("{emby}", language(29999))
types = {
'yesno': d.yesno,
'ok': d.ok,
'notification': d.notification,
'input': d.input
'input': d.input,
'select': d.select,
'numeric': d.numeric
}
return types[type_](**kwargs)

View File

@ -23,7 +23,7 @@ log = logging.getLogger("EMBY."+__name__)
##################################################################################################
class WebSocket_Client(threading.Thread):
class WebSocketClient(threading.Thread):
_shared_state = {}
@ -35,12 +35,12 @@ class WebSocket_Client(threading.Thread):
self.__dict__ = self._shared_state
self.monitor = xbmc.Monitor()
self.doutils = downloadutils.DownloadUtils()
self.client_info = clientinfo.ClientInfo()
self.device_id = self.client_info.get_device_id()
self.library_sync = librarysync.LibrarySync()
threading.Thread.__init__(self)
@ -66,15 +66,15 @@ class WebSocket_Client(threading.Thread):
message_type = result['MessageType']
data = result['Data']
if message_type not in ('SessionEnded'):
if message_type not in ('NotificationAdded', 'SessionEnded'):
# Mute certain events
log.info("Message: %s" % message)
log.info("Message: %s", message)
if message_type == "Play":
if message_type == 'Play':
# A remote control play command has been sent from the server.
self._play_(data)
elif message_type == "Playstate":
elif message_type == 'Playstate':
# A remote control update playstate command has been sent from the server.
self._playstate_(data)
@ -84,16 +84,7 @@ class WebSocket_Client(threading.Thread):
self.library_sync.triage_items("userdata", userdata_list)
elif message_type == "LibraryChanged":
librarySync = self.library_sync
processlist = {
'added': data['ItemsAdded'],
'update': data['ItemsUpdated'],
'remove': data['ItemsRemoved']
}
for action in processlist:
librarySync.triage_items(action, processlist[action])
self._library_changed(data)
elif message_type == "GeneralCommand":
self._general_commands(data)
@ -118,26 +109,26 @@ class WebSocket_Client(threading.Thread):
playlist_ = playlist.Playlist()
if command == "PlayNow":
if command == 'PlayNow':
startat = data.get('StartPositionTicks', 0)
playlist_.playAll(item_ids, startat)
playlist_.play_all(item_ids, startat)
dialog(type_="notification",
heading=lang(29999),
heading="{emby}",
message="%s %s" % (len(item_ids), lang(33004)),
icon="{emby}",
sound=False)
elif command == "PlayNext":
newplaylist = playlist_.modifyPlaylist(item_ids)
elif command == 'PlayNext':
new_playlist = playlist_.modify_playlist(item_ids)
dialog(type_="notification",
heading=lang(29999),
heading="{emby}",
message="%s %s" % (len(item_ids), lang(33005)),
icon="{emby}",
sound=False)
player = xbmc.Player()
if not player.isPlaying():
# Only start the playlist if nothing is playing
player.play(newplaylist)
player.play(new_playlist)
@classmethod
def _playstate_(cls, data):
@ -151,21 +142,36 @@ class WebSocket_Client(threading.Thread):
'Unpause': player.pause,
'Pause': player.pause,
'NextTrack': player.playnext,
'PreviousTrack': player.playprevious,
'Seek': player.seekTime
'PreviousTrack': player.playprevious
}
action = actions[command]
if command == "Seek":
seekto = data['SeekPositionTicks']
seektime = seekto / 10000000.0
action(seektime)
log.info("Seek to %s", seektime)
else:
action()
if command == 'Seek':
seek_to = data['SeekPositionTicks']
seek_time = seek_to / 10000000.0
player.seekTime(seek_time)
log.info("Seek to %s", seek_time)
elif command in actions:
actions[command]()
log.info("Command: %s completed", command)
else:
log.info("Unknown command: %s", command)
return
window('emby_command', value="true")
def _library_changed(self, data):
process_list = {
'added': data['ItemsAdded'],
'update': data['ItemsUpdated'],
'remove': data['ItemsRemoved']
}
for action in process_list:
self.library_sync.triage_items(action, process_list[action])
@classmethod
def _general_commands(cls, data):
@ -177,42 +183,46 @@ class WebSocket_Client(threading.Thread):
player = xbmc.Player()
# These commands need to be reported back
if command == "Mute":
if command == 'Mute':
xbmc.executebuiltin('Mute')
elif command == "Unmute":
elif command == 'Unmute':
xbmc.executebuiltin('Mute')
elif command == "SetVolume":
elif command == 'SetVolume':
volume = arguments['Volume']
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
elif command == "SetAudioStreamIndex":
elif command == 'SetAudioStreamIndex':
index = int(arguments['Index'])
player.setAudioStream(index - 1)
elif command == "SetSubtitleStreamIndex":
embyindex = int(arguments['Index'])
currentFile = player.getPlayingFile()
mapping = window('emby_%s.indexMapping' % currentFile)
elif command == 'SetSubtitleStreamIndex':
emby_index = int(arguments['Index'])
current_file = player.getPlayingFile()
mapping = window('emby_%s.indexMapping' % current_file)
if mapping:
externalIndex = json.loads(mapping)
external_index = json.loads(mapping)
# If there's external subtitles added via playbackutils
for index in externalIndex:
if externalIndex[index] == embyindex:
for index in external_index:
if external_index[index] == emby_index:
player.setSubtitleStream(int(index))
break
else:
# User selected internal subtitles
external = len(externalIndex)
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(external + embyindex - audioTracks - 1)
external = len(external_index)
audio_tracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(external + emby_index - audio_tracks - 1)
else:
# Emby merges audio and subtitle index together
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(index - audioTracks - 1)
audio_tracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(index - audio_tracks - 1)
# Let service know
window('emby_command', value="true")
elif command == "DisplayMessage":
elif command == 'DisplayMessage':
header = arguments['Header']
text = arguments['Text']
@ -222,26 +232,28 @@ class WebSocket_Client(threading.Thread):
icon="{emby}",
time=4000)
elif command == "SendString":
elif command == 'SendString':
params = {
'text': arguments['String'],
'done': False
}
result = JSONRPC("Input.SendText").execute(params)
JSONRPC('Input.SendText').execute(params)
elif command in ("MoveUp", "MoveDown", "MoveRight", "MoveLeft"):
elif command in ('MoveUp', 'MoveDown', 'MoveRight', 'MoveLeft'):
# Commands that should wake up display
actions = {
'MoveUp': "Input.Up",
'MoveDown': "Input.Down",
'MoveRight': "Input.Right",
'MoveLeft': "Input.Left"
}
result = JSONRPC(actions[command]).execute()
JSONRPC(actions[command]).execute()
elif command == "GoHome":
result = JSONRPC("GUI.ActivateWindow").execute({"window":"home"})
elif command == 'GoHome':
JSONRPC('GUI.ActivateWindow').execute({'window': "home"})
else:
builtin = {
@ -262,16 +274,15 @@ class WebSocket_Client(threading.Thread):
'VolumeUp': 'Action(VolumeUp)',
'VolumeDown': 'Action(VolumeDown)',
}
action = builtin.get(command)
if action:
xbmc.executebuiltin(action)
if command in builtin:
xbmc.executebuiltin(builtin[command])
@classmethod
def _server_restarting(cls):
if settings('supressRestartMsg') == "true":
dialog(type_="notification",
heading=lang(29999),
heading="{emby}",
message=lang(33006),
icon="{emby}")
@ -282,6 +293,7 @@ class WebSocket_Client(threading.Thread):
self.doutils.postCapabilities(self.device_id)
def on_error(self, ws, error):
if "10061" in str(error):
# Server is offline
pass
@ -291,7 +303,6 @@ class WebSocket_Client(threading.Thread):
def run(self):
# websocket.enableTrace(True)
user_id = window('emby_currUser')
server = window('emby_server%s' % user_id)
token = window('emby_accessToken%s' % user_id)
@ -305,9 +316,9 @@ class WebSocket_Client(threading.Thread):
log.info("websocket url: %s", websocket_url)
self._client = websocket.WebSocketApp(websocket_url,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close)
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close)
self._client.on_open = self.on_open
log.warn("----===## Starting WebSocketClient ##===----")

View File

@ -25,6 +25,7 @@ import clientinfo
import initialsetup
import kodimonitor
import librarysync
import loghandler
import player
import videonodes
import websocket_client as wsc
@ -32,8 +33,6 @@ from utils import window, settings, dialog, language as lang
#################################################################################################
import loghandler
loghandler.config()
log = logging.getLogger("EMBY.service")
@ -101,7 +100,7 @@ class Service(object):
# Initialize important threads
user = userclient.UserClient()
ws = wsc.WebSocket_Client()
ws = wsc.WebSocketClient()
library = librarysync.LibrarySync()
kplayer = player.Player()
# Sync and progress report
@ -168,10 +167,10 @@ class Service(object):
else:
add = ""
dialog(type_="notification",
heading=lang(29999),
heading="{emby}",
message=("%s %s%s!"
% (lang(33000), user.get_username().decode('utf-8'),
add.decode('utf-8'))),
add.decode('utf-8'))),
icon="{emby}",
time=2000,
sound=False)
@ -236,7 +235,7 @@ class Service(object):
# device going to sleep
if self.websocket_running:
ws.stop_client()
ws = wsc.WebSocket_Client()
ws = wsc.WebSocketClient()
self.websocket_running = False
if self.library_running:
@ -254,7 +253,7 @@ class Service(object):
break
# Alert the user that server is online.
dialog(type_="notification",
heading=lang(29999),
heading="{emby}",
message=lang(33003),
icon="{emby}",
time=2000,
@ -292,12 +291,14 @@ class Service(object):
log.warn("======== STOP %s ========", self.addon_name)
# Delay option
DELAY = int(settings('startupDelay'))
log.warn("Delaying emby startup by: %s sec...", DELAY)
if DELAY and xbmc.Monitor().waitForAbort(DELAY):
# Start the service
log.warn("Abort requested while waiting. Emby for kodi not started.")
else:
Service().service_entry_point()
if __name__ == "__main__":
# Delay option
DELAY = int(settings('startupDelay'))
log.warn("Delaying emby startup by: %s sec...", DELAY)
if DELAY and xbmc.Monitor().waitForAbort(DELAY):
# Start the service
log.warn("Abort requested while waiting. Emby for kodi not started.")
else:
Service().service_entry_point()