289 lines
8.9 KiB
Python
289 lines
8.9 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
"""
|
||
|
|
||
|
Copyright (C) 2013-2014 Team-XBMC
|
||
|
Copyright (C) 2014-2019 Team Kodi
|
||
|
|
||
|
This file is part of service.xbmc.versioncheck
|
||
|
|
||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
See LICENSES/GPL-3.0-or-later.txt for more information.
|
||
|
|
||
|
"""
|
||
|
|
||
|
import sys
|
||
|
|
||
|
import xbmc # pylint: disable=import-error
|
||
|
import xbmcaddon # pylint: disable=import-error
|
||
|
import xbmcgui # pylint: disable=import-error
|
||
|
import xbmcvfs # pylint: disable=import-error
|
||
|
|
||
|
try:
|
||
|
xbmc.translatePath = xbmcvfs.translatePath
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
|
||
|
ADDON = xbmcaddon.Addon('service.xbmc.versioncheck')
|
||
|
ADDON_VERSION = ADDON.getAddonInfo('version')
|
||
|
ADDON_NAME = ADDON.getAddonInfo('name')
|
||
|
if sys.version_info[0] >= 3:
|
||
|
ADDON_PATH = ADDON.getAddonInfo('path')
|
||
|
ADDON_PROFILE = xbmc.translatePath(ADDON.getAddonInfo('profile'))
|
||
|
else:
|
||
|
ADDON_PATH = ADDON.getAddonInfo('path').decode('utf-8')
|
||
|
ADDON_PROFILE = xbmc.translatePath(ADDON.getAddonInfo('profile')).decode('utf-8')
|
||
|
ICON = ADDON.getAddonInfo('icon')
|
||
|
KODI_VERSION_MAJOR = int(xbmc.getInfoLabel('System.BuildVersion')[0:2])
|
||
|
|
||
|
MONITOR = xbmc.Monitor()
|
||
|
|
||
|
|
||
|
# Fixes unicode problems
|
||
|
def string_unicode(text, encoding='utf-8'):
|
||
|
""" Python 2/3 -> unicode/str
|
||
|
|
||
|
:param text: text to convert
|
||
|
:type text: unicode (py2) / str (py3) / bytes (py3)
|
||
|
:param encoding: text encoding
|
||
|
:type encoding: str
|
||
|
:return: converted text
|
||
|
:rtype: unicode (py2) / str (py3)
|
||
|
"""
|
||
|
try:
|
||
|
if sys.version_info[0] >= 3:
|
||
|
text = str(text)
|
||
|
else:
|
||
|
text = unicode(text, encoding) # pylint: disable=undefined-variable
|
||
|
except: # pylint: disable=bare-except
|
||
|
pass
|
||
|
return text
|
||
|
|
||
|
|
||
|
def normalize_string(text):
|
||
|
""" Normalize string
|
||
|
|
||
|
:param text: text to normalize
|
||
|
:type text: unicode (py2) / str (py3) / bytes (py3)
|
||
|
:return: normalized text
|
||
|
:rtype: unicode (py2) / str (py3)
|
||
|
"""
|
||
|
try:
|
||
|
text = unicodedata.normalize('NFKD', string_unicode(text)).encode('ascii', 'ignore') # pylint: disable=undefined-variable
|
||
|
except: # pylint: disable=bare-except
|
||
|
pass
|
||
|
return text
|
||
|
|
||
|
|
||
|
def localise(string_id):
|
||
|
""" Localise string id
|
||
|
|
||
|
:param string_id: id of the string to localise
|
||
|
:type string_id: int
|
||
|
:return: localised string
|
||
|
:rtype: unicode (py2) / str (py3)
|
||
|
"""
|
||
|
string = normalize_string(ADDON.getLocalizedString(string_id))
|
||
|
return string
|
||
|
|
||
|
|
||
|
def log(txt):
|
||
|
""" Log text at xbmc.LOGDEBUG level
|
||
|
|
||
|
:param txt: text to log
|
||
|
:type txt: str / unicode / bytes (py3)
|
||
|
"""
|
||
|
if sys.version_info[0] >= 3:
|
||
|
if isinstance(txt, bytes):
|
||
|
txt = txt.decode('utf-8')
|
||
|
message = '%s: %s' % (ADDON_NAME, txt)
|
||
|
else:
|
||
|
if isinstance(txt, str):
|
||
|
txt = txt.decode('utf-8')
|
||
|
message = (u'%s: %s' % (ADDON_NAME, txt)).encode('utf-8')
|
||
|
xbmc.log(msg=message, level=xbmc.LOGDEBUG)
|
||
|
|
||
|
|
||
|
def notification(heading, message, icon=None, time=15000, sound=True):
|
||
|
""" Create a notification
|
||
|
|
||
|
:param heading: notification heading
|
||
|
:type heading: str
|
||
|
:param message: notification message
|
||
|
:type message: str
|
||
|
:param icon: path and filename for the notification icon
|
||
|
:type icon: str
|
||
|
:param time: time to display notification
|
||
|
:type time: int
|
||
|
:param sound: is notification audible
|
||
|
:type sound: bool
|
||
|
"""
|
||
|
if not icon:
|
||
|
icon = ICON
|
||
|
xbmcgui.Dialog().notification(heading, message, icon, time, sound)
|
||
|
|
||
|
|
||
|
def get_password_from_user():
|
||
|
""" Prompt user to input password
|
||
|
|
||
|
:return: password
|
||
|
:rtype: str
|
||
|
"""
|
||
|
pwd = ''
|
||
|
keyboard = xbmc.Keyboard('', ADDON_NAME + ': ' + localise(32022), True)
|
||
|
keyboard.doModal()
|
||
|
if keyboard.isConfirmed():
|
||
|
pwd = keyboard.getText()
|
||
|
return pwd
|
||
|
|
||
|
|
||
|
def message_upgrade_success():
|
||
|
""" Upgrade success notification
|
||
|
"""
|
||
|
notification(ADDON_NAME, localise(32013))
|
||
|
|
||
|
|
||
|
def message_restart():
|
||
|
""" Prompt user to restart Kodi
|
||
|
"""
|
||
|
if dialog_yes_no(32014):
|
||
|
xbmc.executebuiltin('RestartApp')
|
||
|
|
||
|
|
||
|
def dialog_yes_no(line1=0, line2=0):
|
||
|
""" Prompt user with yes/no dialog
|
||
|
|
||
|
:param line1: string id for the first line of the dialog
|
||
|
:type line1: int
|
||
|
:param line2: string id for the second line of the dialog
|
||
|
:type line2: int
|
||
|
:return: users selection (yes / no)
|
||
|
:rtype: bool
|
||
|
"""
|
||
|
return xbmcgui.Dialog().yesno(ADDON_NAME, '[CR]'.join([localise(line1), localise(line2)]))
|
||
|
|
||
|
|
||
|
def upgrade_message(msg):
|
||
|
""" Prompt user with upgrade suggestion message
|
||
|
|
||
|
:param msg: string id for prompt message
|
||
|
:type msg: int
|
||
|
"""
|
||
|
wait_for_end_of_video()
|
||
|
|
||
|
if ADDON.getSetting('lastnotified_version') < ADDON_VERSION:
|
||
|
xbmcgui.Dialog().ok(
|
||
|
ADDON_NAME,
|
||
|
'[CR]'.join([localise(msg), localise(32001), localise(32002)])
|
||
|
)
|
||
|
else:
|
||
|
log('Already notified one time for upgrading.')
|
||
|
|
||
|
|
||
|
def upgrade_message2(version_installed, version_available, version_stable, old_version):
|
||
|
""" Prompt user with upgrade suggestion message
|
||
|
|
||
|
:param version_installed: currently installed version
|
||
|
:type version_installed: dict
|
||
|
:param version_available: available version
|
||
|
:type version_available: dict
|
||
|
:param version_stable: latest stable version
|
||
|
:type version_stable: dict
|
||
|
:param old_version: whether using an old version
|
||
|
:type old_version: bool / 'stable'
|
||
|
"""
|
||
|
# shorten releasecandidate to rc
|
||
|
if version_installed['tag'] == 'releasecandidate':
|
||
|
version_installed['tag'] = 'rc'
|
||
|
if version_available['tag'] == 'releasecandidate':
|
||
|
version_available['tag'] = 'rc'
|
||
|
# convert json-rpc result to strings for usage
|
||
|
msg_current = '%i.%i %s%s' % (version_installed['major'],
|
||
|
version_installed['minor'],
|
||
|
version_installed['tag'],
|
||
|
version_installed.get('tagversion', ''))
|
||
|
msg_available = version_available['major'] + '.' + version_available['minor'] + ' ' + \
|
||
|
version_available['tag'] + version_available.get('tagversion', '')
|
||
|
msg_stable = version_stable['major'] + '.' + version_stable['minor'] + ' ' + \
|
||
|
version_stable['tag'] + version_stable.get('tagversion', '')
|
||
|
msg = localise(32034) % (msg_current, msg_available)
|
||
|
|
||
|
wait_for_end_of_video()
|
||
|
|
||
|
# hack: convert current version number to stable string
|
||
|
# so users don't get notified again. remove in future
|
||
|
if ADDON.getSetting('lastnotified_version') == '0.1.24':
|
||
|
ADDON.setSetting('lastnotified_stable', msg_stable)
|
||
|
|
||
|
# Show different dialogs depending if there's a newer stable available.
|
||
|
# Also split them between xbmc and kodi notifications to reduce possible confusion.
|
||
|
# People will find out once they visit the website.
|
||
|
# For stable only notify once and when there's a newer stable available.
|
||
|
# Ignore any add-on updates as those only count for != stable
|
||
|
if old_version == 'stable' and ADDON.getSetting('lastnotified_stable') != msg_stable:
|
||
|
if xbmcaddon.Addon('xbmc.addon').getAddonInfo('version') < '13.9.0':
|
||
|
xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32030), localise(32031)]))
|
||
|
else:
|
||
|
xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32032), localise(32033)]))
|
||
|
ADDON.setSetting('lastnotified_stable', msg_stable)
|
||
|
|
||
|
elif old_version != 'stable' and ADDON.getSetting('lastnotified_version') != msg_available:
|
||
|
if xbmcaddon.Addon('xbmc.addon').getAddonInfo('version') < '13.9.0':
|
||
|
# point them to xbmc.org
|
||
|
xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32035), localise(32031)]))
|
||
|
else:
|
||
|
# use kodi.tv
|
||
|
xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32035), localise(32033)]))
|
||
|
|
||
|
ADDON.setSetting('lastnotified_version', msg_available)
|
||
|
|
||
|
else:
|
||
|
log('Already notified one time for upgrading.')
|
||
|
|
||
|
|
||
|
def abort_requested():
|
||
|
""" Kodi 13+ compatible xbmc.Monitor().abortRequested()
|
||
|
|
||
|
:return: whether abort requested
|
||
|
:rtype: bool
|
||
|
"""
|
||
|
if KODI_VERSION_MAJOR > 13:
|
||
|
return MONITOR.abortRequested()
|
||
|
|
||
|
return xbmc.abortRequested
|
||
|
|
||
|
|
||
|
def wait_for_abort(seconds):
|
||
|
""" Kodi 13+ compatible xbmc.Monitor().waitForAbort()
|
||
|
|
||
|
:param seconds: seconds to wait for abort
|
||
|
:type seconds: int / float
|
||
|
:return: whether abort was requested
|
||
|
:rtype: bool
|
||
|
"""
|
||
|
if KODI_VERSION_MAJOR > 13:
|
||
|
return MONITOR.waitForAbort(seconds)
|
||
|
|
||
|
for _ in range(0, seconds * 1000 / 200):
|
||
|
if xbmc.abortRequested:
|
||
|
return True
|
||
|
xbmc.sleep(200)
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
def wait_for_end_of_video():
|
||
|
""" Wait for video playback to end
|
||
|
"""
|
||
|
# Don't show notify while watching a video
|
||
|
while xbmc.Player().isPlayingVideo() and not abort_requested():
|
||
|
if wait_for_abort(1):
|
||
|
# Abort was requested while waiting. We should exit
|
||
|
break
|
||
|
i = 0
|
||
|
while i < 10 and not abort_requested():
|
||
|
if wait_for_abort(1):
|
||
|
# Abort was requested while waiting. We should exit
|
||
|
break
|
||
|
i += 1
|