399 lines
14 KiB
Python
399 lines
14 KiB
Python
# Gnu General Public License - see LICENSE.TXT
|
|
from __future__ import division, absolute_import, print_function, unicode_literals
|
|
|
|
import socket
|
|
import json
|
|
import requests
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import xbmcaddon
|
|
import xbmcgui
|
|
import xbmc
|
|
|
|
from .kodi_utils import HomeWindow
|
|
from .downloadutils import DownloadUtils
|
|
from .loghandler import LazyLogger
|
|
from .utils import datetime_from_string, translate_string, get_version, 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()
|
|
verify_cert = settings.getSetting('verify_cert') == 'true'
|
|
http_timeout = int(settings.getSetting("http_timeout"))
|
|
speed_test_data_size = int(settings.getSetting("speed_test_data_size"))
|
|
test_data_size = speed_test_data_size * 1000000
|
|
|
|
du = DownloadUtils()
|
|
server = du.get_server()
|
|
|
|
url = server + "/playback/bitratetest?size=%s" % test_data_size
|
|
|
|
head = du.get_auth_header(True)
|
|
head["User-Agent"] = "JellyCon-{}".format(get_version())
|
|
|
|
request_details = {
|
|
"stream": True,
|
|
"headers": head
|
|
}
|
|
|
|
if not verify_cert:
|
|
request_details["verify"] = False
|
|
|
|
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 = requests.get(url, **request_details)
|
|
|
|
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 check_safe_delete_available():
|
|
log.debug("check_safe_delete_available")
|
|
|
|
du = DownloadUtils()
|
|
result = du.download_url("{server}/Plugins")
|
|
if result:
|
|
log.debug("Server Plugin List: {0}".format(result))
|
|
|
|
safe_delete_found = False
|
|
for plugin in result:
|
|
if plugin["Name"] == "Safe Delete":
|
|
safe_delete_found = True
|
|
break
|
|
|
|
log.debug("Safe Delete Plugin Available: {0}".format(safe_delete_found))
|
|
home_window = HomeWindow()
|
|
if safe_delete_found:
|
|
home_window.set_property("safe_delete_plugin_available", "true")
|
|
else:
|
|
home_window.clear_property("safe_delete_plugin_available")
|
|
|
|
else:
|
|
log.debug("Error getting server plugin list")
|
|
|
|
|
|
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()
|
|
server_url = ""
|
|
something_changed = False
|
|
du = DownloadUtils()
|
|
|
|
if force is False:
|
|
# if not forcing use server details from settings
|
|
svr = du.get_server()
|
|
if svr is not None:
|
|
server_url = svr
|
|
|
|
# if the server is not set then try to detect it
|
|
if server_url == "":
|
|
|
|
# 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:
|
|
server_url = server_info[return_index]["Address"]
|
|
|
|
if not server_url:
|
|
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 server_url:
|
|
kb.setDefault(server_url)
|
|
else:
|
|
kb.setDefault("http://")
|
|
kb.doModal()
|
|
if kb.isConfirmed():
|
|
server_url = kb.getText()
|
|
else:
|
|
xbmc.executebuiltin("ActivateWindow(Home)")
|
|
return
|
|
|
|
public_lookup_url = "%s/System/Info/Public?format=json" % (server_url)
|
|
|
|
log.debug("Testing_Url: {0}".format(public_lookup_url))
|
|
progress = xbmcgui.DialogProgress()
|
|
progress.create('{} : {}'.format(__addon_name__, translate_string(30376)))
|
|
progress.update(0, translate_string(30377))
|
|
result = du.download_url(public_lookup_url, authenticate=False)
|
|
progress.close()
|
|
|
|
if result:
|
|
xbmcgui.Dialog().ok('{} : {}'.format(__addon_name__, translate_string(30167)),
|
|
server_url)
|
|
break
|
|
else:
|
|
return_index = xbmcgui.Dialog().yesno('{} : {}'.format(__addon_name__, translate_string(30135)),
|
|
server_url,
|
|
translate_string(30371))
|
|
if not return_index:
|
|
xbmc.executebuiltin("ActivateWindow(Home)")
|
|
return
|
|
|
|
log.debug("Selected server: {0}".format(server_url))
|
|
settings.setSetting("server_address", server_url)
|
|
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(server_url, 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()
|
|
|
|
# TODO: Make the authenticate function operate normally. Network rework
|
|
home_window.set_property('password', password)
|
|
|
|
if something_changed:
|
|
home_window = HomeWindow()
|
|
home_window.clear_property("jellycon_widget_reload")
|
|
du.authenticate()
|
|
xbmc.executebuiltin("ActivateWindow(Home)")
|
|
if "estuary_jellycon" in xbmc.getSkinDir():
|
|
xbmc.executebuiltin("SetFocus(9000, 0, absolute)")
|
|
xbmc.executebuiltin("ReloadSkin()")
|
|
|
|
|
|
def user_select(server_url, current_username):
|
|
'''
|
|
Display user selection screen
|
|
'''
|
|
du = DownloadUtils()
|
|
|
|
# Retrieve list of public users from server
|
|
result = du.download_url('{}/Users/Public'.format(server_url), authenticate=False)
|
|
|
|
# Build user display
|
|
selected_id = -1
|
|
users = []
|
|
for user in result:
|
|
user_item = create_user_listitem(du, 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(du, 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)
|
|
user_image = du.get_user_artwork(user, 'Primary')
|
|
if not user_image:
|
|
user_image = "DefaultUser.png"
|
|
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
|