Files
jellycon/resources/lib/server_detect.py
2022-03-09 22:51:38 +01:00

364 lines
13 KiB
Python

# Gnu General Public License - see LICENSE.TXT
from __future__ import division, absolute_import, print_function, unicode_literals
import socket
import json
import time
from datetime import datetime
import xbmcaddon
import xbmcgui
import xbmc
from .kodi_utils import HomeWindow
from .jellyfin import API
from .lazylogger import LazyLogger
from .utils import datetime_from_string, translate_string, save_user_details, load_user_details
log = LazyLogger(__name__)
__addon__ = xbmcaddon.Addon()
__addon_name__ = __addon__.getAddonInfo('name')
def check_connection_speed():
log.debug("check_connection_speed")
settings = xbmcaddon.Addon()
speed_test_data_size = int(settings.getSetting("speed_test_data_size"))
test_data_size = speed_test_data_size * 1000000
user_details = load_user_details()
api = API(
settings.getSetting('server_address'),
user_details.get('user_id'),
user_details.get('token')
)
progress_dialog = xbmcgui.DialogProgress()
message = 'Testing with {0} MB of data'.format(speed_test_data_size)
progress_dialog.create("JellyCon connection speed test", message)
start_time = time.time()
log.debug("Starting Connection Speed Test")
response = api.speedtest(test_data_size)
last_percentage_done = 0
total_data_read = 0
if response.status_code == 200:
for data in response.iter_content(chunk_size=10240):
total_data_read += len(data)
percentage_done = int(float(total_data_read) / float(test_data_size) * 100.0)
if last_percentage_done != percentage_done:
progress_dialog.update(percentage_done)
last_percentage_done = percentage_done
else:
log.error("HTTP response error: {0} {1}".format(response.status_code, response.content))
error_message = "HTTP response error: %s\n%s" % (response.status_code, response.content)
xbmcgui.Dialog().ok("Speed Test Error", error_message)
return -1
total_data_read_kbits = (total_data_read * 8) / 1000
total_time = time.time() - start_time
speed = int(total_data_read_kbits / total_time)
log.debug("Finished Connection Speed Test, speed: {0} total_data: {1}, total_time: {2}".format(speed, total_data_read, total_time))
progress_dialog.close()
del progress_dialog
heading = "Speed Test Result : {0:,} Kbs".format(speed)
message = "Do you want to set this speed as your max stream bitrate for playback?\n"
message += "{0:,} MB over {1} sec".format(int((total_data_read / 1000000)), total_time)
response = xbmcgui.Dialog().yesno(heading, message)
if response:
settings.setSetting("max_stream_bitrate", str(speed))
return speed
def get_server_details():
log.debug("Getting Server Details from Network")
servers = []
message = b"who is JellyfinServer?"
multi_group = ("<broadcast>", 7359)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(4.0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
log.debug("MutliGroup: {0}".format(multi_group))
log.debug("Sending UDP Data: {0}".format(message))
progress = xbmcgui.DialogProgress()
progress.create('{} : {}'.format(__addon_name__, translate_string(30373)))
progress.update(0, translate_string(30374))
xbmc.sleep(1000)
server_count = 0
try:
sock.sendto(message, multi_group)
while True:
try:
server_count += 1
progress.update(server_count * 10, '{}: {}'.format(translate_string(30375), server_count))
xbmc.sleep(1000)
data, addr = sock.recvfrom(1024)
servers.append(json.loads(data))
except:
break
except Exception as e:
log.error("UPD Discovery Error: {0}".format(e))
progress.close()
log.debug("Found Servers: {0}".format(servers))
return servers
def check_server(force=False, change_user=False, notify=False):
log.debug("checkServer Called")
settings = xbmcaddon.Addon()
something_changed = False
# Initialize api object
api = API()
if force is False:
# if not forcing use server details from settings
api.server = settings.getSetting('server_address')
# if the server is not set then try to detect it
if not api.server:
# scan for local server
server_info = get_server_details()
addon = xbmcaddon.Addon()
server_icon = addon.getAddonInfo('icon')
server_list = []
for server in server_info:
server_item = xbmcgui.ListItem(server.get("Name", translate_string(30063)))
sub_line = server.get("Address")
server_item.setLabel2(sub_line)
server_item.setProperty("address", server.get("Address"))
art = {"Thumb": server_icon}
server_item.setArt(art)
server_list.append(server_item)
if len(server_list) > 0:
return_index = xbmcgui.Dialog().select('{} : {}'.format(__addon_name__, translate_string(30166)),
server_list,
useDetails=True)
if return_index != -1:
api.server = server_info[return_index]["Address"]
if not api.server:
return_index = xbmcgui.Dialog().yesno(__addon_name__, '{}\n{}'.format(translate_string(30282), translate_string(30370)))
if not return_index:
xbmc.executebuiltin("ActivateWindow(Home)")
return
while True:
kb = xbmc.Keyboard()
kb.setHeading(translate_string(30372))
if api.server:
kb.setDefault(api.server)
else:
kb.setDefault("http://")
kb.doModal()
if kb.isConfirmed():
api.server = kb.getText()
else:
xbmc.executebuiltin("ActivateWindow(Home)")
return
progress = xbmcgui.DialogProgress()
progress.create('{} : {}'.format(__addon_name__, translate_string(30376)))
progress.update(0, translate_string(30377))
result = api.get('/System/Info/Public')
progress.close()
if result:
xbmcgui.Dialog().ok('{} : {}'.format(__addon_name__, translate_string(30167)),
api.server)
break
else:
return_index = xbmcgui.Dialog().yesno('{} : {}'.format(__addon_name__, translate_string(30135)),
api.server,
translate_string(30371))
if not return_index:
xbmc.executebuiltin("ActivateWindow(Home)")
return
log.debug("Selected server: {0}".format(api.server))
settings.setSetting("server_address", api.server)
something_changed = True
# do we need to change the user
current_username = settings.getSetting('username')
# if asked or we have no current user then show user selection screen
if something_changed or change_user or len(current_username) == 0:
# stop playback when switching users
xbmc.Player().stop()
users, user_selection = user_select(api, current_username)
if user_selection > -1:
something_changed = True
selected_user = users[user_selection]
selected_user_name = selected_user.getLabel()
secured = selected_user.getProperty("secure") == "true"
manual = selected_user.getProperty("manual") == "true"
home_window = HomeWindow()
# If using a manual login, ask for username
if manual:
kb = xbmc.Keyboard()
kb.setHeading(translate_string(30005))
if current_username:
kb.setDefault(current_username)
kb.doModal()
if kb.isConfirmed():
selected_user_name = kb.getText()
log.debug("Manual entered username: {0}".format(selected_user_name))
else:
return
home_window.set_property('user_name', selected_user_name)
user_details = load_user_details()
# Ask for password if user has one
password = ''
if secured and not user_details.get('token'):
kb = xbmc.Keyboard()
kb.setHeading(translate_string(30006))
kb.setHiddenInput(True)
kb.doModal()
if kb.isConfirmed():
password = kb.getText()
if something_changed:
home_window = HomeWindow()
home_window.clear_property("jellycon_widget_reload")
auth_payload = {'username': selected_user_name, 'pw': password}
user = api.authenticate(auth_payload)
token = user.get('AccessToken')
user_id = user.get('User').get('Id')
save_user_details(selected_user_name, user_id, token)
xbmc.executebuiltin("ActivateWindow(Home)")
if "estuary_jellycon" in xbmc.getSkinDir():
xbmc.executebuiltin("SetFocus(9000, 0, absolute)")
xbmc.executebuiltin("ReloadSkin()")
def user_select(api, current_username):
'''
Display user selection screen
'''
# Retrieve list of public users from server
result = api.get('/Users/Public')
# Build user display
selected_id = -1
users = []
for user in result:
user_item = create_user_listitem(api.server, user)
if user_item:
users.append(user_item)
name = user.get("Name")
# Highlight currently logged in user
if current_username == name:
selected_id = len(users) - 1
if current_username:
selection_title = translate_string(30180) + " (" + current_username + ")"
else:
selection_title = translate_string(30180)
# Add manual login item
user_item = xbmcgui.ListItem(translate_string(30365))
art = {"Thumb": "DefaultUser.png"}
user_item.setArt(art)
user_item.setLabel2(translate_string(30366))
user_item.setProperty("secure", "true")
user_item.setProperty("manual", "true")
users.append(user_item)
user_selection = xbmcgui.Dialog().select(selection_title,
users,
preselect=selected_id,
autoclose=20000,
useDetails=True)
return (users, user_selection)
def create_user_listitem(server, user):
'''
Create a user listitem for the user selection screen
'''
config = user.get("Configuration")
if config is not None:
name = user.get("Name")
time_ago = ""
last_active = user.get("LastActivityDate")
# Calculate how long it's been since the user was last active
if last_active:
last_active_date = datetime_from_string(last_active)
ago = datetime.now() - last_active_date
# Check days
if ago.days > 0:
time_ago += ' {}d'.format(ago.days)
# Check minutes
if ago.seconds > 60:
hours = 0
# Check hours
if ago.seconds > 3600:
hours = int(ago.seconds/3600)
time_ago += ' {}h'.format(hours)
minutes = int((ago.seconds - (hours * 3600)) / 60)
time_ago += ' {}m'.format(minutes)
time_ago = time_ago.strip()
if not time_ago:
time_ago = "Active: now"
else:
time_ago = "Active: {} ago".format(time_ago)
user_item = xbmcgui.ListItem(name)
# If the user doesn't have a profile image, user the default
if 'PrimaryImageTag' not in user:
user_image = "DefaultUser.png"
else:
user_id = user.get('Id')
tag = user.get('PrimaryImageTag')
user_image = '{}/Users/{}/Images/Primary?Format=original&tag={}'.format(
server, user_id, tag
)
art = {"Thumb": user_image}
user_item.setArt(art)
sub_line = time_ago
if user.get("HasPassword", False) is True:
user_item.setProperty("secure", "true")
else:
user_item.setProperty("secure", "false")
user_item.setProperty("manual", "false")
user_item.setLabel2(sub_line)
return user_item
return None