Merge branch 'stable-version'
This commit is contained in:
commit
0d77102117
3 changed files with 282 additions and 288 deletions
43
default.py
43
default.py
|
@ -67,32 +67,27 @@ class Main():
|
|||
self.play()
|
||||
|
||||
elif mode == 'ondeck':
|
||||
entrypoint.getOnDeck(itemid,
|
||||
params.get('type'),
|
||||
params.get('tagname'),
|
||||
int(params.get('limit')))
|
||||
entrypoint.on_deck_episodes(itemid,
|
||||
params.get('tagname'),
|
||||
int(params.get('limit')))
|
||||
|
||||
elif mode == 'recentepisodes':
|
||||
entrypoint.getRecentEpisodes(itemid,
|
||||
params.get('type'),
|
||||
params.get('tagname'),
|
||||
int(params.get('limit')))
|
||||
entrypoint.recent_episodes(params.get('type'),
|
||||
params.get('tagname'),
|
||||
int(params.get('limit')))
|
||||
|
||||
elif mode == 'nextup':
|
||||
entrypoint.getNextUpEpisodes(params['tagname'],
|
||||
int(params['limit']))
|
||||
entrypoint.next_up_episodes(params['tagname'],
|
||||
int(params['limit']))
|
||||
|
||||
elif mode == 'inprogressepisodes':
|
||||
entrypoint.getInProgressEpisodes(params['tagname'],
|
||||
int(params['limit']))
|
||||
entrypoint.in_progress_episodes(params['tagname'],
|
||||
int(params['limit']))
|
||||
|
||||
elif mode == 'browseplex':
|
||||
entrypoint.browse_plex(key=params.get('key'),
|
||||
plex_section_id=params.get('id'))
|
||||
|
||||
elif mode == 'getsubfolders':
|
||||
entrypoint.GetSubFolders(itemid)
|
||||
|
||||
elif mode == 'watchlater':
|
||||
entrypoint.watchlater()
|
||||
|
||||
|
@ -106,22 +101,22 @@ class Main():
|
|||
executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID)
|
||||
|
||||
elif mode == 'enterPMS':
|
||||
entrypoint.enterPMS()
|
||||
entrypoint.create_new_pms()
|
||||
|
||||
elif mode == 'reset':
|
||||
reset()
|
||||
|
||||
elif mode == 'togglePlexTV':
|
||||
entrypoint.togglePlexTV()
|
||||
entrypoint.toggle_plex_tv_sign_in()
|
||||
|
||||
elif mode == 'resetauth':
|
||||
entrypoint.resetAuth()
|
||||
entrypoint.reset_authorization()
|
||||
|
||||
elif mode == 'passwords':
|
||||
passwords_xml()
|
||||
|
||||
elif mode == 'switchuser':
|
||||
entrypoint.switchPlexUser()
|
||||
entrypoint.switch_plex_user()
|
||||
|
||||
elif mode in ('manualsync', 'repair'):
|
||||
if window('plex_online') != 'true':
|
||||
|
@ -141,7 +136,7 @@ class Main():
|
|||
plex_command('RUN_LIB_SCAN', 'textures')
|
||||
|
||||
elif mode == 'chooseServer':
|
||||
entrypoint.chooseServer()
|
||||
entrypoint.choose_pms_server()
|
||||
|
||||
elif mode == 'refreshplaylist':
|
||||
log.info('Requesting playlist/nodes refresh')
|
||||
|
@ -157,17 +152,17 @@ class Main():
|
|||
elif '/extrafanart' in argv[0]:
|
||||
plexpath = argv[2][1:]
|
||||
plexid = itemid
|
||||
entrypoint.getExtraFanArt(plexid, plexpath)
|
||||
entrypoint.getVideoFiles(plexid, plexpath)
|
||||
entrypoint.extra_fanart(plexid, plexpath)
|
||||
entrypoint.get_video_files(plexid, plexpath)
|
||||
|
||||
# Called by e.g. 3rd party plugin video extras
|
||||
elif ('/Extras' in argv[0] or '/VideoFiles' in argv[0] or
|
||||
'/Extras' in argv[2]):
|
||||
plexId = itemid or None
|
||||
entrypoint.getVideoFiles(plexId, params)
|
||||
entrypoint.get_video_files(plexId, params)
|
||||
|
||||
else:
|
||||
entrypoint.doMainListing(content_type=params.get('content_type'))
|
||||
entrypoint.show_main_menu(content_type=params.get('content_type'))
|
||||
|
||||
@staticmethod
|
||||
def play():
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Loads of different functions called in SEPARATE Python instances through
|
||||
# e.g. plugin://... calls. Hence be careful to only rely on window variables.
|
||||
#
|
||||
###############################################################################
|
||||
from logging import getLogger
|
||||
from shutil import copyfile
|
||||
|
@ -22,7 +26,7 @@ import json_rpc as js
|
|||
import variables as v
|
||||
|
||||
###############################################################################
|
||||
log = getLogger("PLEX."+__name__)
|
||||
LOG = getLogger("PLEX." + __name__)
|
||||
|
||||
try:
|
||||
HANDLE = int(argv[1])
|
||||
|
@ -32,25 +36,25 @@ except IndexError:
|
|||
###############################################################################
|
||||
|
||||
|
||||
def chooseServer():
|
||||
def choose_pms_server():
|
||||
"""
|
||||
Lets user choose from list of PMS
|
||||
"""
|
||||
log.info("Choosing PMS server requested, starting")
|
||||
LOG.info("Choosing PMS server requested, starting")
|
||||
|
||||
import initialsetup
|
||||
setup = initialsetup.InitialSetup()
|
||||
server = setup.pick_pms(showDialog=True)
|
||||
if server is None:
|
||||
log.error('We did not connect to a new PMS, aborting')
|
||||
LOG.error('We did not connect to a new PMS, aborting')
|
||||
plex_command('SUSPEND_USER_CLIENT', 'False')
|
||||
plex_command('SUSPEND_LIBRARY_THREAD', 'False')
|
||||
return
|
||||
|
||||
log.info("User chose server %s" % server['name'])
|
||||
LOG.info("User chose server %s", server['name'])
|
||||
setup.write_pms_to_settings(server)
|
||||
|
||||
if not __LogOut():
|
||||
if not _log_out():
|
||||
return
|
||||
|
||||
from utils import wipe_database
|
||||
|
@ -58,8 +62,8 @@ def chooseServer():
|
|||
wipe_database()
|
||||
|
||||
# Log in again
|
||||
__LogIn()
|
||||
log.info("Choosing new PMS complete")
|
||||
_log_in()
|
||||
LOG.info("Choosing new PMS complete")
|
||||
# '<PMS> connected'
|
||||
dialog('notification',
|
||||
lang(29999),
|
||||
|
@ -69,9 +73,13 @@ def chooseServer():
|
|||
sound=False)
|
||||
|
||||
|
||||
def togglePlexTV():
|
||||
def toggle_plex_tv_sign_in():
|
||||
"""
|
||||
Signs out of Plex.tv if there was a token saved and thus deletes the token.
|
||||
Or signs in to plex.tv if the user was not logged in before.
|
||||
"""
|
||||
if settings('plexToken'):
|
||||
log.info('Reseting plex.tv credentials in settings')
|
||||
LOG.info('Reseting plex.tv credentials in settings')
|
||||
settings('plexLogin', value="")
|
||||
settings('plexToken', value="")
|
||||
settings('plexid', value="")
|
||||
|
@ -83,7 +91,7 @@ def togglePlexTV():
|
|||
plex_command('PLEX_TOKEN', '')
|
||||
plex_command('PLEX_USERNAME', '')
|
||||
else:
|
||||
log.info('Login to plex.tv')
|
||||
LOG.info('Login to plex.tv')
|
||||
import initialsetup
|
||||
initialsetup.InitialSetup().plex_tv_sign_in()
|
||||
dialog('notification',
|
||||
|
@ -94,27 +102,40 @@ def togglePlexTV():
|
|||
sound=False)
|
||||
|
||||
|
||||
##### DO RESET AUTH #####
|
||||
def resetAuth():
|
||||
# User tried login and failed too many times
|
||||
def reset_authorization():
|
||||
"""
|
||||
User tried login and failed too many times. Reset # of logins
|
||||
"""
|
||||
resp = dialog('yesno', heading="{plex}", line1=lang(39206))
|
||||
if resp == 1:
|
||||
log.info("Reset login attempts.")
|
||||
LOG.info("Reset login attempts.")
|
||||
plex_command('PMS_STATUS', 'Auth')
|
||||
else:
|
||||
executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
|
||||
|
||||
def addDirectoryItem(label, path, folder=True):
|
||||
li = ListItem(label, path=path)
|
||||
li.setThumbnailImage("special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
||||
li.setArt({"fanart":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
||||
li.setArt({"landscape":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE, url=path, listitem=li, isFolder=folder)
|
||||
def directory_item(label, path, folder=True):
|
||||
"""
|
||||
Adds a xbmcplugin.addDirectoryItem() directory itemlistitem
|
||||
"""
|
||||
listitem = ListItem(label, path=path)
|
||||
listitem.setThumbnailImage(
|
||||
"special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
||||
listitem.setArt(
|
||||
{"fanart": "special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
||||
listitem.setArt(
|
||||
{"landscape":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=path,
|
||||
listitem=listitem,
|
||||
isFolder=folder)
|
||||
|
||||
|
||||
def doMainListing(content_type=None):
|
||||
log.debug('Do main listing with content_type: %s' % content_type)
|
||||
def show_main_menu(content_type=None):
|
||||
"""
|
||||
Shows the main PKC menu listing with all libraries, Channel, settings, etc.
|
||||
"""
|
||||
LOG.debug('Do main listing with content_type: %s', content_type)
|
||||
xbmcplugin.setContent(HANDLE, 'files')
|
||||
# Get emby nodes from the window props
|
||||
plexprops = window('Plex.nodes.total')
|
||||
|
@ -133,33 +154,33 @@ def doMainListing(content_type=None):
|
|||
# now we just only show picture nodes in the picture library video
|
||||
# nodes in the video library and all nodes in any other window
|
||||
if node_type == 'photos' and content_type == 'image':
|
||||
addDirectoryItem(label, path)
|
||||
directory_item(label, path)
|
||||
elif (node_type != 'photos' and
|
||||
content_type not in ('image', 'audio')):
|
||||
addDirectoryItem(label, path)
|
||||
directory_item(label, path)
|
||||
|
||||
# Plex Watch later
|
||||
if content_type not in ('image', 'audio'):
|
||||
addDirectoryItem(lang(39211),
|
||||
"plugin://%s?mode=watchlater" % v.ADDON_ID)
|
||||
directory_item(lang(39211),
|
||||
"plugin://%s?mode=watchlater" % v.ADDON_ID)
|
||||
# Plex Channels
|
||||
addDirectoryItem(lang(30173),
|
||||
"plugin://%s?mode=channels" % v.ADDON_ID)
|
||||
directory_item(lang(30173),
|
||||
"plugin://%s?mode=channels" % v.ADDON_ID)
|
||||
# Plex user switch
|
||||
addDirectoryItem('%s%s' % (lang(39200), settings('username')),
|
||||
"plugin://%s?mode=switchuser" % v.ADDON_ID)
|
||||
directory_item('%s%s' % (lang(39200), settings('username')),
|
||||
"plugin://%s?mode=switchuser" % v.ADDON_ID)
|
||||
|
||||
# some extra entries for settings and stuff
|
||||
addDirectoryItem(lang(39201),
|
||||
"plugin://%s?mode=settings" % v.ADDON_ID)
|
||||
addDirectoryItem(lang(39203),
|
||||
"plugin://%s?mode=refreshplaylist" % v.ADDON_ID)
|
||||
addDirectoryItem(lang(39204),
|
||||
"plugin://%s?mode=manualsync" % v.ADDON_ID)
|
||||
directory_item(lang(39201),
|
||||
"plugin://%s?mode=settings" % v.ADDON_ID)
|
||||
directory_item(lang(39203),
|
||||
"plugin://%s?mode=refreshplaylist" % v.ADDON_ID)
|
||||
directory_item(lang(39204),
|
||||
"plugin://%s?mode=manualsync" % v.ADDON_ID)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
def switchPlexUser():
|
||||
def switch_plex_user():
|
||||
"""
|
||||
Signs out currently logged in user (if applicable). Triggers sign-in of a
|
||||
new user
|
||||
|
@ -168,42 +189,30 @@ def switchPlexUser():
|
|||
# Delete any userimages. Since there's always only 1 user: position = 0
|
||||
# position = 0
|
||||
# window('EmbyAdditionalUserImage.%s' % position, clear=True)
|
||||
log.info("Plex home user switch requested")
|
||||
if not __LogOut():
|
||||
LOG.info("Plex home user switch requested")
|
||||
if not _log_out():
|
||||
return
|
||||
|
||||
# First remove playlists of old user
|
||||
from utils import delete_playlists, delete_nodes
|
||||
delete_playlists()
|
||||
# Remove video nodes
|
||||
delete_nodes()
|
||||
__LogIn()
|
||||
_log_in()
|
||||
|
||||
|
||||
#### SHOW SUBFOLDERS FOR NODE #####
|
||||
def GetSubFolders(nodeindex):
|
||||
nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"]
|
||||
for node in nodetypes:
|
||||
title = window('Plex.nodes.%s%s.title' %(nodeindex,node))
|
||||
if title:
|
||||
path = window('Plex.nodes.%s%s.content' %(nodeindex,node))
|
||||
addDirectoryItem(title, path)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
##### LISTITEM SETUP FOR VIDEONODES #####
|
||||
def createListItem(item, append_show_title=False, append_sxxexx=False):
|
||||
log.debug('createListItem called with append_show_title %s, append_sxxexx '
|
||||
'%s, item: %s', append_show_title, append_sxxexx, item)
|
||||
def create_listitem(item, append_show_title=False, append_sxxexx=False):
|
||||
"""
|
||||
Feed with a Kodi json item response to get a xbmcgui.ListItem() with
|
||||
everything set and ready.
|
||||
"""
|
||||
title = item['title']
|
||||
li = ListItem(title)
|
||||
li.setProperty('IsPlayable', 'true')
|
||||
listitem = ListItem(title)
|
||||
listitem.setProperty('IsPlayable', 'true')
|
||||
metadata = {
|
||||
'duration': str(item['runtime']/60),
|
||||
'duration': str(item['runtime'] / 60),
|
||||
'Plot': item['plot'],
|
||||
'Playcount': item['playcount']
|
||||
}
|
||||
|
||||
if 'episode' in item:
|
||||
episode = item['episode']
|
||||
metadata['Episode'] = episode
|
||||
|
@ -211,7 +220,7 @@ def createListItem(item, append_show_title=False, append_sxxexx=False):
|
|||
season = item['season']
|
||||
metadata['Season'] = season
|
||||
if season and episode:
|
||||
li.setProperty('episodeno', 's%.2de%.2d' % (season, episode))
|
||||
listitem.setProperty('episodeno', 's%.2de%.2d' % (season, episode))
|
||||
if append_sxxexx is True:
|
||||
title = 'S%.2dE%.2d - %s' % (season, episode, title)
|
||||
if 'firstaired' in item:
|
||||
|
@ -239,27 +248,30 @@ def createListItem(item, append_show_title=False, append_sxxexx=False):
|
|||
metadata['Title'] = title
|
||||
metadata['mediatype'] = 'episode'
|
||||
metadata['dbid'] = str(item['episodeid'])
|
||||
li.setLabel(title)
|
||||
li.setInfo(type='Video', infoLabels=metadata)
|
||||
listitem.setLabel(title)
|
||||
listitem.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.setArt({'icon': 'DefaultTVShows.png'})
|
||||
li.setProperty('fanart_image', item['art'].get('tvshow.fanart', ''))
|
||||
listitem.setProperty('resumetime', str(item['resume']['position']))
|
||||
listitem.setProperty('totaltime', str(item['resume']['total']))
|
||||
listitem.setArt(item['art'])
|
||||
listitem.setThumbnailImage(item['art'].get('thumb', ''))
|
||||
listitem.setArt({'icon': 'DefaultTVShows.png'})
|
||||
listitem.setProperty('fanart_image', item['art'].get('tvshow.fanart', ''))
|
||||
try:
|
||||
li.addContextMenuItems([(lang(30032), 'XBMC.Action(Info)',)])
|
||||
listitem.addContextMenuItems([(lang(30032), 'XBMC.Action(Info)',)])
|
||||
except TypeError:
|
||||
# Kodi fuck-up
|
||||
pass
|
||||
for key, value in item['streamdetails'].iteritems():
|
||||
for stream in value:
|
||||
li.addStreamInfo(key, stream)
|
||||
return li
|
||||
listitem.addStreamInfo(key, stream)
|
||||
return listitem
|
||||
|
||||
##### GET NEXTUP EPISODES FOR TAGNAME #####
|
||||
def getNextUpEpisodes(tagname, limit):
|
||||
|
||||
def next_up_episodes(tagname, limit):
|
||||
"""
|
||||
List the next up episodes for tagname.
|
||||
"""
|
||||
count = 0
|
||||
# if the addon is called with nextup parameter,
|
||||
# we return the nextepisodes list of the given tagname
|
||||
|
@ -314,15 +326,17 @@ def getNextUpEpisodes(tagname, limit):
|
|||
for episode in js.get_episodes(params):
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=episode['file'],
|
||||
listitem=createListItem(episode))
|
||||
listitem=create_listitem(episode))
|
||||
count += 1
|
||||
if count == limit:
|
||||
break
|
||||
xbmcplugin.endOfDirectory(handle=HANDLE)
|
||||
|
||||
|
||||
##### GET INPROGRESS EPISODES FOR TAGNAME #####
|
||||
def getInProgressEpisodes(tagname, limit):
|
||||
def in_progress_episodes(tagname, limit):
|
||||
"""
|
||||
List the episodes that are in progress for tagname
|
||||
"""
|
||||
count = 0
|
||||
# if the addon is called with inprogressepisodes parameter,
|
||||
# we return the inprogressepisodes list of the given tagname
|
||||
|
@ -346,22 +360,25 @@ def getInProgressEpisodes(tagname, limit):
|
|||
'field': "inprogress",
|
||||
'value': ""},
|
||||
'properties': ["title", "playcount", "season", "episode",
|
||||
"showtitle", "plot", "file", "rating", "resume",
|
||||
"tvshowid", "art", "cast", "streamdetails", "firstaired",
|
||||
"runtime", "writer", "dateadded", "lastplayed"]
|
||||
"showtitle", "plot", "file", "rating", "resume",
|
||||
"tvshowid", "art", "cast", "streamdetails",
|
||||
"firstaired", "runtime", "writer", "dateadded",
|
||||
"lastplayed"]
|
||||
}
|
||||
for episode in js.get_episodes(params):
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=episode['file'],
|
||||
listitem=createListItem(episode))
|
||||
listitem=create_listitem(episode))
|
||||
count += 1
|
||||
if count == limit:
|
||||
break
|
||||
xbmcplugin.endOfDirectory(handle=HANDLE)
|
||||
|
||||
##### GET RECENT EPISODES FOR TAGNAME #####
|
||||
# def getRecentEpisodes(tagname, limit):
|
||||
def getRecentEpisodes(viewid, mediatype, tagname, limit):
|
||||
|
||||
def recent_episodes(mediatype, tagname, limit):
|
||||
"""
|
||||
List the recently added episodes for tagname
|
||||
"""
|
||||
count = 0
|
||||
# if the addon is called with recentepisodes parameter,
|
||||
# we return the recentepisodes list of the given tagname
|
||||
|
@ -369,13 +386,13 @@ def getRecentEpisodes(viewid, mediatype, tagname, limit):
|
|||
append_show_title = settings('RecentTvAppendShow') == 'true'
|
||||
append_sxxexx = settings('RecentTvAppendSeason') == 'true'
|
||||
# First we get a list of all the TV shows - filtered by tag
|
||||
allshowsIds = set()
|
||||
show_ids = set()
|
||||
params = {
|
||||
'sort': {'order': "descending", 'method': "dateadded"},
|
||||
'filter': {'operator': "is", 'field': "tag", 'value': "%s" % tagname},
|
||||
}
|
||||
for tv_show in js.get_tv_shows(params):
|
||||
allshowsIds.add(tv_show['tvshowid'])
|
||||
show_ids.add(tv_show['tvshowid'])
|
||||
params = {
|
||||
'sort': {'order': "descending", 'method': "dateadded"},
|
||||
'properties': ["title", "playcount", "season", "episode", "showtitle",
|
||||
|
@ -391,28 +408,27 @@ def getRecentEpisodes(viewid, mediatype, tagname, limit):
|
|||
'value': "1"
|
||||
}
|
||||
for episode in js.get_episodes(params):
|
||||
if episode['tvshowid'] in allshowsIds:
|
||||
listitem = createListItem(episode,
|
||||
append_show_title=append_show_title,
|
||||
append_sxxexx=append_sxxexx)
|
||||
xbmcplugin.addDirectoryItem(
|
||||
handle=HANDLE,
|
||||
url=episode['file'],
|
||||
listitem=listitem)
|
||||
if episode['tvshowid'] in show_ids:
|
||||
listitem = create_listitem(episode,
|
||||
append_show_title=append_show_title,
|
||||
append_sxxexx=append_sxxexx)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=episode['file'],
|
||||
listitem=listitem)
|
||||
count += 1
|
||||
if count == limit:
|
||||
break
|
||||
xbmcplugin.endOfDirectory(handle=HANDLE)
|
||||
|
||||
|
||||
def getVideoFiles(plexId, params):
|
||||
def get_video_files(plex_id, params):
|
||||
"""
|
||||
GET VIDEO EXTRAS FOR LISTITEM
|
||||
|
||||
returns the video files for the item as plugin listing, can be used for
|
||||
browsing the actual files or videoextras etc.
|
||||
"""
|
||||
if plexId is None:
|
||||
if plex_id is None:
|
||||
filename = params.get('filename')
|
||||
if filename is not None:
|
||||
filename = filename[0]
|
||||
|
@ -420,19 +436,19 @@ def getVideoFiles(plexId, params):
|
|||
regex = re.compile(r'''library/metadata/(\d+)''')
|
||||
filename = regex.findall(filename)
|
||||
try:
|
||||
plexId = filename[0]
|
||||
plex_id = filename[0]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
if plexId is None:
|
||||
log.info('No Plex ID found, abort getting Extras')
|
||||
if plex_id is None:
|
||||
LOG.info('No Plex ID found, abort getting Extras')
|
||||
return xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
item = GetPlexMetadata(plexId)
|
||||
item = GetPlexMetadata(plex_id)
|
||||
try:
|
||||
path = item[0][0][0].attrib['file']
|
||||
except:
|
||||
log.error('Could not get file path for item %s' % plexId)
|
||||
except (TypeError, IndexError, AttributeError, KeyError):
|
||||
LOG.error('Could not get file path for item %s', plex_id)
|
||||
return xbmcplugin.endOfDirectory(HANDLE)
|
||||
# Assign network protocol
|
||||
if path.startswith('\\\\'):
|
||||
|
@ -447,82 +463,80 @@ def getVideoFiles(plexId, params):
|
|||
for root, dirs, files in walk(path):
|
||||
for directory in dirs:
|
||||
item_path = try_encode(join(root, directory))
|
||||
li = ListItem(item_path, path=item_path)
|
||||
listitem = ListItem(item_path, path=item_path)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=item_path,
|
||||
listitem=li,
|
||||
listitem=listitem,
|
||||
isFolder=True)
|
||||
for file in files:
|
||||
item_path = try_encode(join(root, file))
|
||||
li = ListItem(item_path, path=item_path)
|
||||
listitem = ListItem(item_path, path=item_path)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=file,
|
||||
listitem=li)
|
||||
listitem=listitem)
|
||||
break
|
||||
else:
|
||||
log.error('Kodi cannot access folder %s' % path)
|
||||
LOG.error('Kodi cannot access folder %s', path)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
@catch_exceptions(warnuser=False)
|
||||
def getExtraFanArt(plexid, plexPath):
|
||||
def extra_fanart(plex_id, plex_path):
|
||||
"""
|
||||
Get extrafanart for listitem
|
||||
will be called by skinhelper script to get the extrafanart
|
||||
for tvshows we get the plexid just from the path
|
||||
for tvshows we get the plex_id just from the path
|
||||
"""
|
||||
log.debug('Called with plexid: %s, plexPath: %s' % (plexid, plexPath))
|
||||
if not plexid:
|
||||
if "plugin.video.plexkodiconnect" in plexPath:
|
||||
plexid = plexPath.split("/")[-2]
|
||||
if not plexid:
|
||||
log.error('Could not get a plexid, aborting')
|
||||
LOG.debug('Called with plex_id: %s, plex_path: %s', plex_id, plex_path)
|
||||
if not plex_id:
|
||||
if "plugin.video.plexkodiconnect" in plex_path:
|
||||
plex_id = plex_path.split("/")[-2]
|
||||
if not plex_id:
|
||||
LOG.error('Could not get a plex_id, aborting')
|
||||
return xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
# We need to store the images locally for this to work
|
||||
# because of the caching system in xbmc
|
||||
fanartDir = try_decode(translatePath(
|
||||
"special://thumbnails/plex/%s/" % plexid))
|
||||
if not exists_dir(fanartDir):
|
||||
fanart_dir = try_decode(translatePath(
|
||||
"special://thumbnails/plex/%s/" % plex_id))
|
||||
if not exists_dir(fanart_dir):
|
||||
# Download the images to the cache directory
|
||||
makedirs(fanartDir)
|
||||
xml = GetPlexMetadata(plexid)
|
||||
makedirs(fanart_dir)
|
||||
xml = GetPlexMetadata(plex_id)
|
||||
if xml is None:
|
||||
log.error('Could not download metadata for %s' % plexid)
|
||||
LOG.error('Could not download metadata for %s', plex_id)
|
||||
return xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
api = API(xml[0])
|
||||
backdrops = api.artwork()['Backdrop']
|
||||
for count, backdrop in enumerate(backdrops):
|
||||
# Same ordering as in artwork
|
||||
fanartFile = try_encode(join(fanartDir, "fanart%.3d.jpg" % count))
|
||||
li = ListItem("%.3d" % count, path=fanartFile)
|
||||
art_file = try_encode(join(fanart_dir, "fanart%.3d.jpg" % count))
|
||||
listitem = ListItem("%.3d" % count, path=art_file)
|
||||
xbmcplugin.addDirectoryItem(
|
||||
handle=HANDLE,
|
||||
url=fanartFile,
|
||||
listitem=li)
|
||||
copyfile(backdrop, try_decode(fanartFile))
|
||||
url=art_file,
|
||||
listitem=listitem)
|
||||
copyfile(backdrop, try_decode(art_file))
|
||||
else:
|
||||
log.info("Found cached backdrop.")
|
||||
LOG.info("Found cached backdrop.")
|
||||
# Use existing cached images
|
||||
for root, dirs, files in walk(fanartDir):
|
||||
for root, _, files in walk(fanart_dir):
|
||||
for file in files:
|
||||
fanartFile = try_encode(join(root, file))
|
||||
li = ListItem(file, path=fanartFile)
|
||||
art_file = try_encode(join(root, file))
|
||||
listitem = ListItem(file, path=art_file)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=fanartFile,
|
||||
listitem=li)
|
||||
url=art_file,
|
||||
listitem=listitem)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
def getOnDeck(viewid, mediatype, tagname, limit):
|
||||
def on_deck_episodes(viewid, tagname, limit):
|
||||
"""
|
||||
Retrieves Plex On Deck items, currently only for TV shows
|
||||
|
||||
Input:
|
||||
viewid: Plex id of the library section, e.g. '1'
|
||||
mediatype: Kodi mediatype, e.g. 'tvshows', 'movies',
|
||||
'homevideos', 'photos'
|
||||
tagname: Name of the Plex library, e.g. "My Movies"
|
||||
limit: Max. number of items to retrieve, e.g. 50
|
||||
"""
|
||||
|
@ -536,7 +550,7 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
|||
while window('plex_authenticated') != 'true':
|
||||
counter += 1
|
||||
if counter == 300:
|
||||
log.error('Aborting On Deck view, we were not authenticated '
|
||||
LOG.error('Aborting On Deck view, we were not authenticated '
|
||||
'for the PMS')
|
||||
xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
return
|
||||
|
@ -544,7 +558,7 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
|||
xml = downloadutils.DownloadUtils().downloadUrl(
|
||||
'{server}/library/sections/%s/onDeck' % viewid)
|
||||
if xml in (None, 401):
|
||||
log.error('Could not download PMS xml for view %s' % viewid)
|
||||
LOG.error('Could not download PMS xml for view %s', viewid)
|
||||
xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
return
|
||||
direct_paths = settings('useDirectPaths') == '1'
|
||||
|
@ -632,9 +646,9 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
|||
continue
|
||||
for episode in episodes:
|
||||
# There will always be only 1 episode ('limit=1')
|
||||
listitem = createListItem(episode,
|
||||
append_show_title=append_show_title,
|
||||
append_sxxexx=append_sxxexx)
|
||||
listitem = create_listitem(episode,
|
||||
append_show_title=append_show_title,
|
||||
append_sxxexx=append_sxxexx)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=episode['file'],
|
||||
listitem=listitem,
|
||||
|
@ -650,10 +664,10 @@ def watchlater():
|
|||
Listing for plex.tv Watch Later section (if signed in to plex.tv)
|
||||
"""
|
||||
if window('plex_token') == '':
|
||||
log.error('No watch later - not signed in to plex.tv')
|
||||
LOG.error('No watch later - not signed in to plex.tv')
|
||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
if window('plex_restricteduser') == 'true':
|
||||
log.error('No watch later - restricted user')
|
||||
LOG.error('No watch later - restricted user')
|
||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
|
||||
xml = downloadutils.DownloadUtils().downloadUrl(
|
||||
|
@ -661,10 +675,10 @@ def watchlater():
|
|||
authenticate=False,
|
||||
headerOptions={'X-Plex-Token': window('plex_token')})
|
||||
if xml in (None, 401):
|
||||
log.error('Could not download watch later list from plex.tv')
|
||||
LOG.error('Could not download watch later list from plex.tv')
|
||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
|
||||
log.info('Displaying watch later plex.tv items')
|
||||
LOG.info('Displaying watch later plex.tv items')
|
||||
xbmcplugin.setContent(HANDLE, 'movies')
|
||||
direct_paths = settings('useDirectPaths') == '1'
|
||||
for item in xml:
|
||||
|
@ -683,10 +697,10 @@ def channels():
|
|||
try:
|
||||
xml[0].attrib
|
||||
except (ValueError, AttributeError, IndexError, TypeError):
|
||||
log.error('Could not download Plex Channels')
|
||||
LOG.error('Could not download Plex Channels')
|
||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
|
||||
log.info('Displaying Plex Channels')
|
||||
LOG.info('Displaying Plex Channels')
|
||||
xbmcplugin.setContent(HANDLE, 'files')
|
||||
for method in v.SORT_METHODS_DIRECTORY:
|
||||
xbmcplugin.addSortMethod(HANDLE, getattr(xbmcplugin, method))
|
||||
|
@ -709,7 +723,7 @@ def browse_plex(key=None, plex_section_id=None):
|
|||
try:
|
||||
xml[0].attrib
|
||||
except (ValueError, AttributeError, IndexError, TypeError):
|
||||
log.error('Could not browse to %s' % key)
|
||||
LOG.error('Could not browse to %s', key)
|
||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
||||
|
||||
photos = False
|
||||
|
@ -855,19 +869,19 @@ def extras(plex_id):
|
|||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
def enterPMS():
|
||||
def create_new_pms():
|
||||
"""
|
||||
Opens dialogs for the user the plug in the PMS details
|
||||
"""
|
||||
# "Enter your Plex Media Server's IP or URL. Examples are:"
|
||||
dialog('ok', lang(29999), lang(39215), '192.168.1.2', 'plex.myServer.org')
|
||||
ip = dialog('input', "Enter PMS IP or URL")
|
||||
if ip == '':
|
||||
address = dialog('input', "Enter PMS IP or URL")
|
||||
if address == '':
|
||||
return
|
||||
port = dialog('input', "Enter PMS port", '32400', type='{numeric}')
|
||||
if port == '':
|
||||
return
|
||||
url = '%s:%s' % (ip, port)
|
||||
url = '%s:%s' % (address, port)
|
||||
# "Does your Plex Media Server support SSL connections?
|
||||
# (https instead of http)"
|
||||
https = dialog('yesno', lang(29999), lang(39217))
|
||||
|
@ -876,9 +890,8 @@ def enterPMS():
|
|||
else:
|
||||
url = 'http://%s' % url
|
||||
https = 'true' if https else 'false'
|
||||
|
||||
machineIdentifier = GetMachineIdentifier(url)
|
||||
if machineIdentifier is None:
|
||||
machine_identifier = GetMachineIdentifier(url)
|
||||
if machine_identifier is None:
|
||||
# "Error contacting url
|
||||
# Abort (Yes) or save address anyway (No)"
|
||||
if dialog('yesno',
|
||||
|
@ -888,22 +901,22 @@ def enterPMS():
|
|||
else:
|
||||
settings('plex_machineIdentifier', '')
|
||||
else:
|
||||
settings('plex_machineIdentifier', machineIdentifier)
|
||||
log.info('Set new PMS to https %s, ip %s, port %s, machineIdentifier %s'
|
||||
% (https, ip, port, machineIdentifier))
|
||||
settings('plex_machineIdentifier', machine_identifier)
|
||||
LOG.info('Set new PMS to https %s, address %s, port %s, machineId %s',
|
||||
https, address, port, machine_identifier)
|
||||
settings('https', value=https)
|
||||
settings('ipaddress', value=ip)
|
||||
settings('ipaddress', value=address)
|
||||
settings('port', value=port)
|
||||
# Chances are this is a local PMS, so disable SSL certificate check
|
||||
settings('sslverify', value='false')
|
||||
|
||||
# Sign out to trigger new login
|
||||
if __LogOut():
|
||||
if _log_out():
|
||||
# Only login again if logout was successful
|
||||
__LogIn()
|
||||
_log_in()
|
||||
|
||||
|
||||
def __LogIn():
|
||||
def _log_in():
|
||||
"""
|
||||
Resets (clears) window properties to enable (re-)login
|
||||
|
||||
|
@ -915,7 +928,7 @@ def __LogIn():
|
|||
plex_command('SUSPEND_USER_CLIENT', 'False')
|
||||
|
||||
|
||||
def __LogOut():
|
||||
def _log_out():
|
||||
"""
|
||||
Finishes lib scans, logs out user.
|
||||
|
||||
|
@ -938,11 +951,11 @@ def __LogOut():
|
|||
dialog('ok', lang(29999), lang(39208))
|
||||
# Resuming threads, just in case
|
||||
plex_command('SUSPEND_LIBRARY_THREAD', 'False')
|
||||
log.error("Could not stop library sync, aborting")
|
||||
LOG.error("Could not stop library sync, aborting")
|
||||
return False
|
||||
counter += 1
|
||||
sleep(50)
|
||||
log.debug("Successfully stopped library sync")
|
||||
LOG.debug("Successfully stopped library sync")
|
||||
|
||||
counter = 0
|
||||
# Log out currently signed in user:
|
||||
|
@ -953,7 +966,7 @@ def __LogOut():
|
|||
if counter > 100:
|
||||
# 'Failed to reset PKC. Try to restart Kodi.'
|
||||
dialog('ok', lang(29999), lang(39208))
|
||||
log.error("Could not sign out user, aborting")
|
||||
LOG.error("Could not sign out user, aborting")
|
||||
return False
|
||||
counter += 1
|
||||
sleep(50)
|
||||
|
|
|
@ -27,8 +27,10 @@ try:
|
|||
from ssl import SSLError
|
||||
HAVE_SSL = True
|
||||
except ImportError:
|
||||
# dummy class of SSLError for ssl none-support environment.
|
||||
class SSLError(Exception):
|
||||
"""
|
||||
Dummy class of SSLError for ssl none-support environment.
|
||||
"""
|
||||
pass
|
||||
|
||||
HAVE_SSL = False
|
||||
|
@ -50,7 +52,7 @@ import utils
|
|||
|
||||
###############################################################################
|
||||
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
LOG = logging.getLogger("PLEX." + __name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -95,28 +97,31 @@ class WebSocketConnectionClosedException(WebSocketException):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class WebSocketTimeoutException(WebSocketException):
|
||||
"""
|
||||
WebSocketTimeoutException will be raised at socket timeout during read/write data.
|
||||
WebSocketTimeoutException will be raised at socket timeout during read and
|
||||
write data.
|
||||
"""
|
||||
pass
|
||||
|
||||
default_timeout = None
|
||||
traceEnabled = False
|
||||
|
||||
DEFAULT_TIMEOUT = None
|
||||
TRACE_ENABLED = False
|
||||
|
||||
|
||||
def enableTrace(tracable):
|
||||
def enable_trace(tracable):
|
||||
"""
|
||||
turn on/off the tracability.
|
||||
|
||||
tracable: boolean value. if set True, tracability is enabled.
|
||||
"""
|
||||
global traceEnabled
|
||||
traceEnabled = tracable
|
||||
global TRACE_ENABLED
|
||||
TRACE_ENABLED = tracable
|
||||
if tracable:
|
||||
if not log.handlers:
|
||||
log.addHandler(logging.StreamHandler())
|
||||
log.setLevel(logging.DEBUG)
|
||||
if not LOG.handlers:
|
||||
LOG.addHandler(logging.StreamHandler())
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def setdefaulttimeout(timeout):
|
||||
|
@ -125,15 +130,15 @@ def setdefaulttimeout(timeout):
|
|||
|
||||
timeout: default socket timeout time. This value is second.
|
||||
"""
|
||||
global default_timeout
|
||||
default_timeout = timeout
|
||||
global DEFAULT_TIMEOUT
|
||||
DEFAULT_TIMEOUT = timeout
|
||||
|
||||
|
||||
def getdefaulttimeout():
|
||||
"""
|
||||
Return the global timeout setting(second) to connect.
|
||||
"""
|
||||
return default_timeout
|
||||
return DEFAULT_TIMEOUT
|
||||
|
||||
|
||||
def _parse_url(url):
|
||||
|
@ -185,7 +190,8 @@ def create_connection(url, timeout=None, **options):
|
|||
|
||||
Connect to url and return the WebSocket object.
|
||||
Passing optional timeout parameter will set the timeout on the socket.
|
||||
If no timeout is supplied, the global default timeout setting returned by getdefauttimeout() is used.
|
||||
If no timeout is supplied, the global default timeout setting returned by
|
||||
getdefauttimeout() is used.
|
||||
You can customize using 'options'.
|
||||
If you set "header" list object, you can set your own custom header.
|
||||
|
||||
|
@ -195,21 +201,23 @@ def create_connection(url, timeout=None, **options):
|
|||
|
||||
|
||||
timeout: socket timeout time. This value is integer.
|
||||
if you set None for this value, it means "use default_timeout value"
|
||||
if you set None for this value, it means "use DEFAULT_TIMEOUT
|
||||
value"
|
||||
|
||||
options: current support option is only "header".
|
||||
if you set header as dict value, the custom HTTP headers are added.
|
||||
if you set header as dict value, the custom HTTP headers are added
|
||||
"""
|
||||
sockopt = options.get("sockopt", [])
|
||||
sslopt = options.get("sslopt", {})
|
||||
websock = WebSocket(sockopt=sockopt, sslopt=sslopt)
|
||||
websock.settimeout(timeout if timeout is not None else default_timeout)
|
||||
websock.settimeout(timeout if timeout is not None else DEFAULT_TIMEOUT)
|
||||
websock.connect(url, **options)
|
||||
return websock
|
||||
|
||||
_MAX_INTEGER = (1 << 32) -1
|
||||
|
||||
_MAX_INTEGER = (1 << 32) - 1
|
||||
_AVAILABLE_KEY_CHARS = range(0x21, 0x2f + 1) + range(0x3a, 0x7e + 1)
|
||||
_MAX_CHAR_BYTE = (1<<8) -1
|
||||
_MAX_CHAR_BYTE = (1 << 8) - 1
|
||||
|
||||
# ref. Websocket gets an update, and it breaks stuff.
|
||||
# http://axod.blogspot.com/2010/06/websocket-gets-update-and-it-breaks.html
|
||||
|
@ -220,10 +228,7 @@ def _create_sec_websocket_key():
|
|||
return base64.encodestring(uid.bytes).strip()
|
||||
|
||||
|
||||
_HEADERS_TO_CHECK = {
|
||||
"upgrade": "websocket",
|
||||
"connection": "upgrade",
|
||||
}
|
||||
_HEADERS_TO_CHECK = {"upgrade": "websocket", "connection": "upgrade"}
|
||||
|
||||
|
||||
class ABNF(object):
|
||||
|
@ -234,16 +239,16 @@ class ABNF(object):
|
|||
"""
|
||||
|
||||
# operation code values.
|
||||
OPCODE_CONT = 0x0
|
||||
OPCODE_TEXT = 0x1
|
||||
OPCODE_CONT = 0x0
|
||||
OPCODE_TEXT = 0x1
|
||||
OPCODE_BINARY = 0x2
|
||||
OPCODE_CLOSE = 0x8
|
||||
OPCODE_PING = 0x9
|
||||
OPCODE_PONG = 0xa
|
||||
OPCODE_CLOSE = 0x8
|
||||
OPCODE_PING = 0x9
|
||||
OPCODE_PONG = 0xa
|
||||
|
||||
# available operation code value tuple
|
||||
OPCODES = (OPCODE_CONT, OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE,
|
||||
OPCODE_PING, OPCODE_PONG)
|
||||
OPCODE_PING, OPCODE_PONG)
|
||||
|
||||
# opcode human readable string
|
||||
OPCODE_MAP = {
|
||||
|
@ -253,10 +258,10 @@ class ABNF(object):
|
|||
OPCODE_CLOSE: "close",
|
||||
OPCODE_PING: "ping",
|
||||
OPCODE_PONG: "pong"
|
||||
}
|
||||
}
|
||||
|
||||
# data length threashold.
|
||||
LENGTH_7 = 0x7d
|
||||
LENGTH_7 = 0x7d
|
||||
LENGTH_16 = 1 << 16
|
||||
LENGTH_63 = 1 << 63
|
||||
|
||||
|
@ -277,8 +282,8 @@ class ABNF(object):
|
|||
|
||||
def __str__(self):
|
||||
return "fin=" + str(self.fin) \
|
||||
+ " opcode=" + str(self.opcode) \
|
||||
+ " data=" + str(self.data)
|
||||
+ " opcode=" + str(self.opcode) \
|
||||
+ " data=" + str(self.data)
|
||||
|
||||
@staticmethod
|
||||
def create_frame(data, opcode):
|
||||
|
@ -308,9 +313,9 @@ class ABNF(object):
|
|||
if length >= ABNF.LENGTH_63:
|
||||
raise ValueError("data is too long")
|
||||
|
||||
frame_header = chr(self.fin << 7
|
||||
| self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4
|
||||
| self.opcode)
|
||||
frame_header = chr(self.fin << 7 |
|
||||
self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4 |
|
||||
self.opcode)
|
||||
if length < ABNF.LENGTH_7:
|
||||
frame_header += chr(self.mask << 7 | length)
|
||||
elif length < ABNF.LENGTH_16:
|
||||
|
@ -395,6 +400,9 @@ class WebSocket(object):
|
|||
self._cont_data = None
|
||||
|
||||
def fileno(self):
|
||||
"""
|
||||
Returns sock.fileno()
|
||||
"""
|
||||
return self.sock.fileno()
|
||||
|
||||
def set_mask_key(self, func):
|
||||
|
@ -438,7 +446,7 @@ class WebSocket(object):
|
|||
|
||||
timeout: socket timeout time. This value is integer.
|
||||
if you set None for this value,
|
||||
it means "use default_timeout value"
|
||||
it means "use DEFAULT_TIMEOUT value"
|
||||
|
||||
options: current support option is only "header".
|
||||
if you set header as dict value,
|
||||
|
@ -487,10 +495,10 @@ class WebSocket(object):
|
|||
|
||||
header_str = "\r\n".join(headers)
|
||||
self._send(header_str)
|
||||
if traceEnabled:
|
||||
log.debug("--- request header ---")
|
||||
log.debug(header_str)
|
||||
log.debug("-----------------------")
|
||||
if TRACE_ENABLED:
|
||||
LOG.debug("--- request header ---")
|
||||
LOG.debug(header_str)
|
||||
LOG.debug("-----------------------")
|
||||
|
||||
status, resp_headers = self._read_headers()
|
||||
if status != 101:
|
||||
|
@ -526,16 +534,16 @@ class WebSocket(object):
|
|||
def _read_headers(self):
|
||||
status = None
|
||||
headers = {}
|
||||
if traceEnabled:
|
||||
log.debug("--- response header ---")
|
||||
if TRACE_ENABLED:
|
||||
LOG.debug("--- response header ---")
|
||||
|
||||
while True:
|
||||
line = self._recv_line()
|
||||
if line == "\r\n":
|
||||
break
|
||||
line = line.strip()
|
||||
if traceEnabled:
|
||||
log.debug(line)
|
||||
if TRACE_ENABLED:
|
||||
LOG.debug(line)
|
||||
if not status:
|
||||
status_info = line.split(" ", 2)
|
||||
status = int(status_info[1])
|
||||
|
@ -547,8 +555,8 @@ class WebSocket(object):
|
|||
else:
|
||||
raise WebSocketException("Invalid header")
|
||||
|
||||
if traceEnabled:
|
||||
log.debug("-----------------------")
|
||||
if TRACE_ENABLED:
|
||||
LOG.debug("-----------------------")
|
||||
|
||||
return status, headers
|
||||
|
||||
|
@ -567,14 +575,17 @@ class WebSocket(object):
|
|||
frame.get_mask_key = self.get_mask_key
|
||||
data = frame.format()
|
||||
length = len(data)
|
||||
if traceEnabled:
|
||||
log.debug("send: " + repr(data))
|
||||
if TRACE_ENABLED:
|
||||
LOG.debug("send: %s", repr(data))
|
||||
while data:
|
||||
l = self._send(data)
|
||||
data = data[l:]
|
||||
return length
|
||||
|
||||
def send_binary(self, payload):
|
||||
"""
|
||||
send the payload
|
||||
"""
|
||||
return self.send(payload, ABNF.OPCODE_BINARY)
|
||||
|
||||
def ping(self, payload=""):
|
||||
|
@ -693,34 +704,10 @@ class WebSocket(object):
|
|||
|
||||
reason: the reason to close. This must be string.
|
||||
"""
|
||||
|
||||
try:
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
except:
|
||||
pass
|
||||
|
||||
'''
|
||||
if self.connected:
|
||||
if status < 0 or status >= ABNF.LENGTH_16:
|
||||
raise ValueError("code is invalid range")
|
||||
|
||||
try:
|
||||
self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
|
||||
timeout = self.sock.gettimeout()
|
||||
self.sock.settimeout(3)
|
||||
try:
|
||||
frame = self.recv_frame()
|
||||
if log.isEnabledFor(logging.ERROR):
|
||||
recv_status = struct.unpack("!H", frame.data)[0]
|
||||
if recv_status != STATUS_NORMAL:
|
||||
log.error("close status: " + repr(recv_status))
|
||||
except:
|
||||
pass
|
||||
self.sock.settimeout(timeout)
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
except:
|
||||
pass
|
||||
'''
|
||||
self._closeInternal()
|
||||
|
||||
def _closeInternal(self):
|
||||
|
@ -752,7 +739,6 @@ class WebSocket(object):
|
|||
raise WebSocketConnectionClosedException()
|
||||
return bytes_
|
||||
|
||||
|
||||
def _recv_strict(self, bufsize):
|
||||
shortage = bufsize - sum(len(x) for x in self._recv_buffer)
|
||||
while shortage > 0:
|
||||
|
@ -767,7 +753,6 @@ class WebSocket(object):
|
|||
self._recv_buffer = [unified[bufsize:]]
|
||||
return unified[:bufsize]
|
||||
|
||||
|
||||
def _recv_line(self):
|
||||
line = []
|
||||
while True:
|
||||
|
@ -846,9 +831,11 @@ class WebSocketApp(object):
|
|||
run event loop for WebSocket framework.
|
||||
This loop is infinite loop and is alive during websocket is available.
|
||||
sockopt: values for socket.setsockopt.
|
||||
sockopt must be tuple and each element is argument of sock.setscokopt.
|
||||
sockopt must be tuple and each element is argument of
|
||||
sock.setscokopt.
|
||||
sslopt: ssl socket optional dict.
|
||||
ping_interval: automatically send "ping" command every specified period(second)
|
||||
ping_interval: automatically send "ping" command every specified
|
||||
period(second)
|
||||
if set to 0, not send automatically.
|
||||
"""
|
||||
if sockopt is None:
|
||||
|
@ -861,26 +848,26 @@ class WebSocketApp(object):
|
|||
self.keep_running = True
|
||||
|
||||
try:
|
||||
self.sock = WebSocket(self.get_mask_key, sockopt=sockopt, sslopt=sslopt)
|
||||
self.sock.settimeout(default_timeout)
|
||||
self.sock = WebSocket(self.get_mask_key,
|
||||
sockopt=sockopt,
|
||||
sslopt=sslopt)
|
||||
self.sock.settimeout(DEFAULT_TIMEOUT)
|
||||
self.sock.connect(self.url, header=self.header)
|
||||
self._callback(self.on_open)
|
||||
|
||||
if ping_interval:
|
||||
thread = threading.Thread(target=self._send_ping, args=(ping_interval,))
|
||||
thread = threading.Thread(target=self._send_ping,
|
||||
args=(ping_interval,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
while self.keep_running:
|
||||
|
||||
try:
|
||||
data = self.sock.recv()
|
||||
|
||||
if data is None or self.keep_running == False:
|
||||
if data is None or self.keep_running is False:
|
||||
break
|
||||
self._callback(self.on_message, data)
|
||||
except Exception, e:
|
||||
#print str(e.args[0])
|
||||
if "timed out" not in e.args[0]:
|
||||
raise e
|
||||
|
||||
|
@ -898,19 +885,18 @@ class WebSocketApp(object):
|
|||
try:
|
||||
callback(self, *args)
|
||||
except Exception, e:
|
||||
log.error(e)
|
||||
if True:#log.isEnabledFor(logging.DEBUG):
|
||||
_, _, tb = sys.exc_info()
|
||||
traceback.print_tb(tb)
|
||||
LOG.error(e)
|
||||
_, _, tb = sys.exc_info()
|
||||
traceback.print_tb(tb)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
enableTrace(True)
|
||||
ws = create_connection("ws://echo.websocket.org/")
|
||||
print("Sending 'Hello, World'...")
|
||||
ws.send("Hello, World")
|
||||
print("Sent")
|
||||
print("Receiving...")
|
||||
result = ws.recv()
|
||||
print("Received '%s'" % result)
|
||||
ws.close()
|
||||
enable_trace(True)
|
||||
WEBSOCKET = create_connection("ws://echo.websocket.org/")
|
||||
LOG.info("Sending 'Hello, World'...")
|
||||
WEBSOCKET.send("Hello, World")
|
||||
LOG.info("Sent")
|
||||
LOG.info("Receiving...")
|
||||
RESULT = WEBSOCKET.recv()
|
||||
LOG.info("Received '%s'", RESULT)
|
||||
WEBSOCKET.close()
|
||||
|
|
Loading…
Reference in a new issue