From b945459dfbd9370423cce06a3da729cd112410aa Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Thu, 8 Sep 2016 22:13:25 -0500 Subject: [PATCH] Pylint (#59) --- contextmenu.py | 321 ++++++++++++++++-------------- default.py | 173 ++++++++-------- resources/lib/playbackutils.py | 12 +- resources/lib/player.py | 2 +- resources/lib/playlist.py | 178 +++++++---------- resources/lib/utils.py | 6 +- resources/lib/websocket_client.py | 143 +++++++------ service.py | 31 +-- 8 files changed, 447 insertions(+), 419 deletions(-) diff --git a/contextmenu.py b/contextmenu.py index 454c7387..15663fe6 100644 --- a/contextmenu.py +++ b/contextmenu.py @@ -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') \ No newline at end of file + log.info("plugin.video.emby contextmenu started") + ContextMenu() + log.info("plugin.video.emby contextmenu stopped") diff --git a/default.py b/default.py index e11c867c..44a818e0 100644 --- a/default.py +++ b/default.py @@ -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') \ No newline at end of file + log.info("plugin.video.emby stopped") diff --git a/resources/lib/playbackutils.py b/resources/lib/playbackutils.py index 31be8d6c..d36b4b33 100644 --- a/resources/lib/playbackutils.py +++ b/resources/lib/playbackutils.py @@ -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 diff --git a/resources/lib/player.py b/resources/lib/player.py index ba512c18..c3e5a45c 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -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.") diff --git a/resources/lib/playlist.py b/resources/lib/playlist.py index 6f40fa71..0a534c06 100644 --- a/resources/lib/playlist.py +++ b/resources/lib/playlist.py @@ -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))) \ No newline at end of file + log.debug(JSONRPC('Playlist.Remove').execute(params)) diff --git a/resources/lib/utils.py b/resources/lib/utils.py index ba226d61..320edd17 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -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) diff --git a/resources/lib/websocket_client.py b/resources/lib/websocket_client.py index eba226d2..f8ab6a68 100644 --- a/resources/lib/websocket_client.py +++ b/resources/lib/websocket_client.py @@ -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 ##===----") diff --git a/service.py b/service.py index 7bcbe799..4d277839 100644 --- a/service.py +++ b/service.py @@ -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()