September 2018 Update
Added - Koding AIO to repo as addons depend on it Updated - DefCon now has 2018 talks in
This commit is contained in:
908
script.module.python.koding.aio/lib/koding/systemtools.py
Normal file
908
script.module.python.koding.aio/lib/koding/systemtools.py
Normal file
@@ -0,0 +1,908 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# script.module.python.koding.aio
|
||||
# Python Koding AIO (c) by TOTALREVOLUTION LTD (support@trmc.freshdesk.com)
|
||||
|
||||
# Python Koding AIO is licensed under a
|
||||
# Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see http://creativecommons.org/licenses/by-nc-nd/4.0.
|
||||
|
||||
# Please make sure you've read and understood the license, this code can NOT be used commercially
|
||||
# and it can NOT be modified and redistributed. If you're found to be in breach of this license
|
||||
# then any affected add-ons will be blacklisted and will not be able to work on the same system
|
||||
# as any other add-ons which use this code. Thank you for your cooperation.
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmcvfs
|
||||
try:
|
||||
from vartools import Data_Type
|
||||
except:
|
||||
pass
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Cleanup_Textures(frequency=14,use_count=10):
|
||||
"""
|
||||
This will check for any cached artwork and wipe if it's not been accessed more than 10 times in the past x amount of days.
|
||||
|
||||
CODE: Cleanup_Textures([frequency, use_count])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
frequency - This is an optional integer, be default it checks for any
|
||||
images not accessed in 14 days but you can use any amount of days here.
|
||||
|
||||
use_count - This is an optional integer, be default it checks for any
|
||||
images not accessed more than 10 times. If you want to be more ruthless
|
||||
and remove all images not accessed in the past x amount of days then set this very high.
|
||||
|
||||
EXAMPLE CODE:
|
||||
dialog.ok('Clean Textures','We are going to clear any old cached images not accessed at least 10 times in the past 5 days')
|
||||
koding.Cleanup_Textures(frequency=5)
|
||||
~"""
|
||||
try: from sqlite3 import dbapi2 as database
|
||||
except: from pysqlite2 import dbapi2 as database
|
||||
from filetools import DB_Path_Check
|
||||
|
||||
db = DB_Path_Check('Textures')
|
||||
xbmc.log('### DB_PATH: %s' % db)
|
||||
conn = database.connect(db, timeout = 10, detect_types=database.PARSE_DECLTYPES, check_same_thread = False)
|
||||
conn.row_factory = database.Row
|
||||
c = conn.cursor()
|
||||
|
||||
# Set paramaters to check in db, cull = the datetime (we've set it to 14 days) and useCount is the amount of times the file has been accessed
|
||||
cull = datetime.datetime.today() - datetime.timedelta(days = frequency)
|
||||
|
||||
# Create an array to store paths for images and ids for database
|
||||
ids = []
|
||||
images = []
|
||||
|
||||
c.execute("SELECT idtexture FROM sizes WHERE usecount < ? AND lastusetime < ?", (use_count, str(cull)))
|
||||
|
||||
for row in c:
|
||||
ids.append(row["idtexture"])
|
||||
|
||||
for id in ids:
|
||||
c.execute("SELECT cachedurl FROM texture WHERE id = ?", (id,))
|
||||
for row in c:
|
||||
images.append(row["cachedurl"])
|
||||
|
||||
|
||||
# Clean up database
|
||||
for id in ids:
|
||||
c.execute("DELETE FROM sizes WHERE idtexture = ?", (id,))
|
||||
c.execute("DELETE FROM texture WHERE id = ?", (id,))
|
||||
|
||||
c.execute("VACUUM")
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
xbmc.log("### Automatic Cache Removal: %d Old Textures removed" % len(images))
|
||||
|
||||
# Delete files
|
||||
thumbfolder = 'special://home/userdata/Thumbnails'
|
||||
for image in images:
|
||||
path = os.path.join(thumbfolder, image)
|
||||
try:
|
||||
xbmcvfs.delete(path)
|
||||
except:
|
||||
xbmc.log(Last_Error())
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Current_Profile():
|
||||
"""
|
||||
This will return the current running profile, it's only one line of code but this is for my benefit as much as
|
||||
anyone else's. I use this function quite a lot and keep forgetting the code so figured it would be easier to
|
||||
just write a simple function for it :)
|
||||
|
||||
CODE: Current_Profile()
|
||||
|
||||
EXAMPLE CODE:
|
||||
profile = koding.Current_Profile()
|
||||
dialog.ok('CURRENT PROFILE','Your current running profile is:','[COLOR=dodgerblue]%s[/COLOR]' % profile)
|
||||
~"""
|
||||
|
||||
return xbmc.getInfoLabel('System.ProfileName')
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Force_Close():
|
||||
"""
|
||||
Force close Kodi, should only be used in extreme circumstances.
|
||||
|
||||
CODE: Force_Close()
|
||||
|
||||
EXAMPLE CODE:
|
||||
if dialog.yesno('FORCE CLOSE','Are you sure you want to forcably close Kodi? This could potentially cause corruption if system tasks are taking place in background.'):
|
||||
koding.Force_Close()
|
||||
~"""
|
||||
os._exit(1)
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Get_ID(setid=False):
|
||||
"""
|
||||
A simple function to set user id and group id to the current running App
|
||||
for system commands. For example if you're using the subprocess command
|
||||
you could send through the preexec_fn paramater as koding.Get_ID(setid=True).
|
||||
This function will also return the uid and gid in form of a dictionary.
|
||||
|
||||
CODE: Get_ID([setid])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
(*) setid - By default this is set to False but if set to True it
|
||||
will set the ids (to be used for subprocess commands)
|
||||
|
||||
EXAMPLE CODE:
|
||||
ids = Get_ID(setid=False)
|
||||
if ids:
|
||||
uid = ids['uid']
|
||||
gid = ids['gid']
|
||||
dialog.ok('USER & GROUP ID','User ID: %s'%uid, 'Group ID: %s'%gid)
|
||||
else:
|
||||
dialog.ok('USER & GROUP ID','This function is not applicable to your system. We\'ve been sent back a return of False to indicate this function does not exist on your os.')
|
||||
~"""
|
||||
try:
|
||||
uid = os.getuid()
|
||||
gid = os.getgid()
|
||||
if setid:
|
||||
os.setgid(uid)
|
||||
os.setuid(gid)
|
||||
if not setid:
|
||||
return {"uid":uid,"gid":gid}
|
||||
except:
|
||||
return False
|
||||
#----------------------------------------------------------------
|
||||
def Get_Mac(protocol = 'eth'):
|
||||
cont = False
|
||||
vpn_check = False
|
||||
counter = 0
|
||||
mac = ''
|
||||
while len(mac)!=17 and counter < 5:
|
||||
if sys.platform == 'win32':
|
||||
for line in os.popen("ipconfig /all"):
|
||||
if protocol == 'wifi':
|
||||
if line.startswith('Wireless LAN adapter Wi'):
|
||||
cont = True
|
||||
if line.lstrip().startswith('Physical Address') and cont:
|
||||
mac = line.split(':')[1].strip().replace('-',':').replace(' ','')
|
||||
break
|
||||
else:
|
||||
if line.lstrip().startswith('Description'):
|
||||
if not 'VPN' in line:
|
||||
vpn_check = True
|
||||
if line.lstrip().startswith('Physical Address') and vpn_check:
|
||||
mac = line.split(':')[1].strip().replace('-',':').replace(' ','')
|
||||
vpn_check = False
|
||||
break
|
||||
|
||||
elif sys.platform == 'darwin':
|
||||
if protocol == 'wifi':
|
||||
for line in os.popen("ifconfig en0 | grep ether"):
|
||||
if line.lstrip().startswith('ether'):
|
||||
mac = line.split('ether')[1].strip().replace('-',':').replace(' ','')
|
||||
break
|
||||
else:
|
||||
for line in os.popen("ifconfig en1 | grep ether"):
|
||||
if line.lstrip().startswith('ether'):
|
||||
mac = line.split('ether')[1].strip().replace('-',':').replace(' ','')
|
||||
break
|
||||
|
||||
elif xbmc.getCondVisibility('System.Platform.Android'):
|
||||
try:
|
||||
if protocol == 'wifi':
|
||||
readfile = open('/sys/class/net/wlan0/address', mode='r')
|
||||
if protocol != 'wifi':
|
||||
readfile = open('/sys/class/net/eth0/address', mode='r')
|
||||
mac = readfile.read()
|
||||
readfile.close()
|
||||
mac = mac.strip()
|
||||
mac = mac.replace(' ','')
|
||||
mac = mac[:17]
|
||||
except:
|
||||
mac = ''
|
||||
|
||||
else:
|
||||
mac = ''
|
||||
if protocol == 'wifi':
|
||||
for line in os.popen("/sbin/ifconfig"):
|
||||
if line.find('wlan0') > -1:
|
||||
mac = line.split()[4].strip()
|
||||
break
|
||||
elif line.startswith('en'):
|
||||
if 'Ethernet'in line and 'HWaddr' in line:
|
||||
mac = line.split('HWaddr')[1].strip()
|
||||
break
|
||||
else:
|
||||
for line in os.popen("/sbin/ifconfig"):
|
||||
if line.find('eth0') > -1:
|
||||
mac = line.split()[4].strip()
|
||||
break
|
||||
elif line.startswith('wl'):
|
||||
if 'Ethernet'in line and 'HWaddr' in line:
|
||||
mac = line.split('HWaddr')[1].strip()
|
||||
break
|
||||
counter += 1
|
||||
xbmc.log('attempt no.%s %s mac: %s'%(counter,protocol,mac),2)
|
||||
if len(mac) != 17:
|
||||
counter = 0
|
||||
while counter < 5 and len(mac) != 17:
|
||||
mac = xbmc.getInfoLabel('Network.MacAddress')
|
||||
xbmc.log('MAC (backup): %s'%mac,2)
|
||||
xbmc.sleep(100)
|
||||
counter += 1
|
||||
if len(mac) != 17:
|
||||
return 'Unknown'
|
||||
else:
|
||||
return mac
|
||||
#-----------------------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Grab_Log(log_type = 'std', formatting = 'original', sort_order = 'reverse'):
|
||||
"""
|
||||
This will grab the log file contents, works on all systems even forked kodi.
|
||||
|
||||
CODE: Grab_Log([log_type, formatting, sort_order])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
log_type - This is optional, if not set you will get the current log.
|
||||
If you would prefer the old log set this to 'old'
|
||||
|
||||
formatting - By default you'll just get a default log but you can set
|
||||
this to 'warnings', 'notices', 'errors' to filter by only those error types.
|
||||
Notices will return in blue, warnings in gold and errors in red.
|
||||
You can use as many of the formatting values as you want, just separate by an
|
||||
underscore such as 'warnings_errors'. If using anything other than the
|
||||
default in here your log will returned in order of newest log activity first
|
||||
(reversed order). You can also use 'clean' as an option and that will just
|
||||
return the full log but with clean text formatting and in reverse order.
|
||||
|
||||
sort_order - This will only work if you've sent through an argument other
|
||||
than 'original' for the formatting. By default the log will be shown in
|
||||
'reverse' order but you can set this to 'original' if you prefer ascending
|
||||
timestamp ordering like a normal log.
|
||||
|
||||
EXAMPLE CODE:
|
||||
my_log = koding.Grab_Log()
|
||||
dialog.ok('KODI LOG LOOP','Press OK to see various logging options, every 5 seconds it will show a new log style.')
|
||||
koding.Text_Box('CURRENT LOG FILE (ORIGINAL)',my_log)
|
||||
xbmc.sleep(5000)
|
||||
my_log = koding.Grab_Log(formatting='clean', sort_order='reverse')
|
||||
koding.Text_Box('CURRENT LOG FILE (clean in reverse order)',my_log)
|
||||
xbmc.sleep(5000)
|
||||
my_log = koding.Grab_Log(formatting='errors_warnings', sort_order='reverse')
|
||||
koding.Text_Box('CURRENT LOG FILE (erros & warnings only - reversed)',my_log)
|
||||
xbmc.sleep(5000)
|
||||
old_log = koding.Grab_Log(log_type='old')
|
||||
koding.Text_Box('OLD LOG FILE',old_log)
|
||||
~"""
|
||||
from filetools import Physical_Path, Text_File
|
||||
log_path = Physical_Path('special://logpath/')
|
||||
logfilepath = os.listdir(log_path)
|
||||
finalfile = 0
|
||||
for item in logfilepath:
|
||||
cont = False
|
||||
if item.endswith('.log') and not item.endswith('.old.log') and log_type == 'std':
|
||||
mylog = os.path.join(log_path,item)
|
||||
cont = True
|
||||
elif item.endswith('.old.log') and log_type == 'old':
|
||||
mylog = os.path.join(log_path,item)
|
||||
cont = True
|
||||
if cont:
|
||||
lastmodified = xbmcvfs.Stat(mylog).st_mtime()
|
||||
if lastmodified>finalfile:
|
||||
finalfile = lastmodified
|
||||
logfile = mylog
|
||||
|
||||
logtext = Text_File(logfile, 'r')
|
||||
|
||||
if formatting != 'original':
|
||||
logtext_final = ''
|
||||
|
||||
with open(logfile) as f:
|
||||
log_array = f.readlines()
|
||||
log_array = [line.strip() for line in log_array]
|
||||
|
||||
if sort_order == 'reverse':
|
||||
log_array = reversed(log_array)
|
||||
|
||||
for line in log_array:
|
||||
if ('warnings' in formatting or 'clean' in formatting) and 'WARNING:' in line:
|
||||
logtext_final += line.replace('WARNING:', '[COLOR=gold]WARNING:[/COLOR]')+'\n'
|
||||
if ('errors' in formatting or 'clean' in formatting) and 'ERROR:' in line:
|
||||
logtext_final += line.replace('ERROR:', '[COLOR=red]ERROR:[/COLOR]')+'\n'
|
||||
if ('notices' in formatting or 'clean' in formatting) and 'NOTICE:' in line:
|
||||
logtext_final += line.replace('NOTICE:', '[COLOR=dodgerblue]NOTICE:[/COLOR]')+'\n'
|
||||
|
||||
logtext = logtext_final
|
||||
|
||||
return logtext
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Last_Error():
|
||||
"""
|
||||
Return details of the last error produced, perfect for try/except statements
|
||||
|
||||
CODE: Last_Error()
|
||||
|
||||
EXAMPLE CODE:
|
||||
try:
|
||||
xbmc.log(this_should_error)
|
||||
except:
|
||||
koding.Text_Box('ERROR MESSAGE',Last_Error())
|
||||
~"""
|
||||
|
||||
import traceback
|
||||
error = traceback.format_exc()
|
||||
return error
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Network_Settings():
|
||||
"""
|
||||
Attempt to open the WiFi/network settings for the current running operating system.
|
||||
|
||||
I have no access to any iOS based systems so if anybody wants to add support for
|
||||
that and you know the working code please contact me at info@totalrevolution.tv
|
||||
The Linux one is also currently untested and of course there are many different
|
||||
distros so if you know of any improved code please do pass on. Thank you.
|
||||
|
||||
CODE: Network_Settings()
|
||||
|
||||
EXAMPLE CODE:
|
||||
koding.Network_Settings()
|
||||
~"""
|
||||
content = Grab_Log()
|
||||
if xbmc.getCondVisibility('System.Platform.Android'):
|
||||
xbmc.executebuiltin('StartAndroidActivity(,android.settings.WIFI_SETTINGS)')
|
||||
|
||||
elif xbmc.getCondVisibility('System.Platform.OSX'):
|
||||
os.system('open /System/Library/PreferencePanes/Network.prefPane/')
|
||||
|
||||
elif xbmc.getCondVisibility('System.Platform.Windows'):
|
||||
os.system('ncpa.cpl')
|
||||
|
||||
elif 'Running on OpenELEC' in content or 'Running on LibreELEC' in content:
|
||||
|
||||
if xbmc.getCondVisibility("System.HasAddon(service.openelec.settings)") or xbmc.getCondVisibility("System.HasAddon(service.libreelec.settings)"):
|
||||
if xbmc.getCondVisibility("System.HasAddon(service.openelec.settings)"):
|
||||
xbmcaddon.Addon(id='service.openelec.settings').getAddonInfo('name')
|
||||
xbmc.executebuiltin('RunAddon(service.openelec.settings)')
|
||||
elif xbmc.getCondVisibility("System.HasAddon(service.libreelec.settings)"):
|
||||
xbmcaddon.Addon(id='service.libreelec.settings').getAddonInfo('name')
|
||||
xbmc.executebuiltin('RunAddon(service.libreelec.settings)')
|
||||
xbmc.sleep(1500)
|
||||
xbmc.executebuiltin('Control.SetFocus(1000,2)')
|
||||
xbmc.sleep(500)
|
||||
xbmc.executebuiltin('Control.SetFocus(1200,0)')
|
||||
|
||||
elif xbmc.getCondVisibility('System.Platform.Linux'):
|
||||
os.system('nm-connection-editor')
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Python_Version():
|
||||
"""
|
||||
Return the current version of Python as a string. Very useful if you need
|
||||
to find out whether or not to return https links (Python 2.6 is not SSL friendly).
|
||||
|
||||
CODE: Python_Version()
|
||||
|
||||
EXAMPLE CODE:
|
||||
py_version = koding.Python_Version()
|
||||
dialog.ok('PYTHON VERSION','You are currently running:','Python v.%s'%py_version)
|
||||
~"""
|
||||
py_version = '%s.%s'%(sys.version_info[0],sys.version_info[1])
|
||||
return py_version
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Refresh(r_mode=['addons', 'repos'], profile_name='default'):
|
||||
"""
|
||||
Refresh a number of items in kodi, choose the order they are
|
||||
executed in by putting first in your r_mode. For example if you
|
||||
want to refresh addons then repo and then the profile you would
|
||||
send through a list in the order you want them to be executed.
|
||||
|
||||
CODE: Refresh(r_mode, [profile])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
r_mode - This is the types of "refresh you want to perform",
|
||||
you can send through just one item or a list of items from the
|
||||
list below. If you want a sleep between each action just put a
|
||||
'~' followed by amount of milliseconds after the r_mode. For example
|
||||
r_mode=['addons~3000', 'repos~2000', 'profile']. This would refresh
|
||||
the addons, wait 2 seconds then refresh the repos, wait 3 seconds then
|
||||
reload the profile. The default is set to do a force refresh on
|
||||
addons and repositories - ['addons', 'repos'].
|
||||
|
||||
'addons': This will perform the 'UpdateLocalAddons' command.
|
||||
|
||||
'container': This will refresh the contents of the page.
|
||||
|
||||
'profile': This will refresh the current profile or if
|
||||
the profile_name param is set it will load that.
|
||||
|
||||
'repos': This will perform the 'UpdateAddonRepos' command.
|
||||
|
||||
'skin': This will perform the 'ReloadSkin' command.
|
||||
|
||||
profile_name - If you're sending through the option to refresh
|
||||
a profile it will reload the current running profile by default
|
||||
but you can pass through a profile name here.
|
||||
|
||||
EXAMPLE CODE:
|
||||
dialog.ok('RELOAD SKIN','We will now attempt to update the addons, pause 3s, update repos and pause 2s then reload the skin. Press OK to continue.')
|
||||
koding.Refresh(r_mode=['addons~3000', 'repos~2000', 'skin'])
|
||||
xbmc.sleep(2000)
|
||||
dialog.ok('COMPLETE','Ok that wasn\'t the best test to perform as you can\'t physically see any visible changes other than the skin refreshing so you\'ll just have to trust us that it worked!')
|
||||
~"""
|
||||
from vartools import Data_Type
|
||||
if profile_name == 'default':
|
||||
profile_name = Current_Profile()
|
||||
|
||||
data_type = Data_Type(r_mode)
|
||||
if data_type == 'str':
|
||||
r_mode = [r_mode]
|
||||
|
||||
for item in r_mode:
|
||||
sleeper = 0
|
||||
if '~' in item:
|
||||
item, sleeper = item.split('~')
|
||||
sleeper = int(sleeper)
|
||||
if item =='addons':
|
||||
xbmc.executebuiltin('UpdateLocalAddons')
|
||||
if item =='repos':
|
||||
xbmc.executebuiltin('UpdateAddonRepos')
|
||||
if item =='container':
|
||||
xbmc.executebuiltin('Container.Refresh')
|
||||
if item =='skin':
|
||||
xbmc.executebuiltin('ReloadSkin')
|
||||
if item =='profile':
|
||||
xbmc.executebuiltin('LoadProfile(%s)' % profile_name)
|
||||
if sleeper:
|
||||
xbmc.sleep(sleeper)
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Requirements(dependency):
|
||||
"""
|
||||
Return the min and max versions of built-in kodi dependencies required by
|
||||
the running version of Kodi (xbmc.gui, xbmc.python etc.), The return will
|
||||
be a dictionary with the keys 'min' and 'max'.
|
||||
|
||||
CODE: Requirements(dependency)
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
(*) dependency - This is the dependency you want to check.
|
||||
You can check any built-in dependency which has backwards-compatibility
|
||||
but the most commonly used are xbmc.gui and xbmc.python.
|
||||
|
||||
EXAMPLE CODE:
|
||||
xbmc_gui = Requirements('xbmc.gui')
|
||||
xbmc_python = Requirements('xbmc.python')
|
||||
dialog.ok('DEPENDENCIES','[COLOR=dodgerblue]xbmc.gui[/COLOR] Min: %s Max: %s'%(xbmc_gui['min'],xbmc_gui['max']),'[COLOR=dodgerblue]xbmc.python[/COLOR] Min: %s Max: %s'%(xbmc_python['min'],xbmc_python['max']))
|
||||
~"""
|
||||
from filetools import Physical_Path,Text_File
|
||||
from vartools import Find_In_Text
|
||||
kodi_ver = xbmc.getInfoLabel("System.BuildVersion")[:2]
|
||||
# Dictionary used for fallback if local file not accessible (AFTV for example)
|
||||
defaults = {'15':{'xbmc.gui':['5.3.0','5.9.0'], 'xbmc.python':['2.1.0','2.20.0']}, '16':{'xbmc.gui':['5.10.0','5.10.0'], 'xbmc.python':['2.1.0','2.24.0']}, '17':{'xbmc.gui':['5.12.0','5.12.0'], 'xbmc.python':['2.1.0','2.25.0']}}
|
||||
root = 'special://xbmc/addons'
|
||||
dep_path = os.path.join(root,dependency,'addon.xml')
|
||||
content = Text_File(dep_path,'r')
|
||||
try:
|
||||
max_ver = Find_In_Text(content=content,start='version="',end='"')[1]
|
||||
min_ver = Find_In_Text(content=content,start='abi="',end='"')[0]
|
||||
except:
|
||||
xbmc.log(repr(defaults[kodi_ver]),2)
|
||||
try:
|
||||
max_ver = defaults[kodi_ver][dependency][1]
|
||||
min_ver = defaults[kodi_ver][dependency][0]
|
||||
except:
|
||||
max_ver = 'unknown'
|
||||
min_ver = 'unknown'
|
||||
xbmc.log('%s min: %s'%(dependency,min_ver),2)
|
||||
xbmc.log('%s max: %s'%(dependency,max_ver),2)
|
||||
return {'min':min_ver,"max":max_ver}
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Running_App():
|
||||
"""
|
||||
Return the Kodi app name you're running, useful for fork compatibility
|
||||
|
||||
CODE: Running_App()
|
||||
|
||||
EXAMPLE CODE:
|
||||
my_kodi = koding.Running_App()
|
||||
kodi_ver = xbmc.getInfoLabel("System.BuildVersion")
|
||||
dialog.ok('KODI VERSION','You are running:','[COLOR=dodgerblue]%s[/COLOR] - v.%s' % (my_kodi, kodi_ver))
|
||||
~"""
|
||||
root_folder = xbmc.translatePath('special://xbmc')
|
||||
xbmc.log(root_folder)
|
||||
if '/cache' in root_folder:
|
||||
root_folder = root_folder.split('/cache')[0]
|
||||
root_folder = root_folder.split('/')
|
||||
if root_folder[len(root_folder)-1] == '':
|
||||
root_folder.pop()
|
||||
finalitem = len(root_folder)-1
|
||||
running = root_folder[finalitem]
|
||||
return running
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Set_Setting(setting, setting_type='kodi_setting', value = 'true'):
|
||||
"""
|
||||
Use this to set built-in kodi settings via JSON or set skin settings.
|
||||
|
||||
CODE: Set_Setting(setting, [setting_type, value])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
setting_type - The type of setting type you want to change. By default
|
||||
it's set to 'kodi_setting', see below for more info.
|
||||
|
||||
AVAILALE VALUES:
|
||||
|
||||
'string' : sets a skin string, requires a value.
|
||||
|
||||
'bool_true' : sets a skin boolean to true, no value required.
|
||||
|
||||
'bool_false' sets a skin boolean to false, no value required.
|
||||
|
||||
'kodi_setting' : sets values found in guisettings.xml. Requires
|
||||
a string of 'true' or 'false' for the value paramater.
|
||||
|
||||
'addon_enable' : enables/disables an addon. Requires a string of
|
||||
'true' (enable) or 'false' (disable) as the value. You will get a
|
||||
return of True/False on whether successul. Depending on your requirements
|
||||
you may prefer to use the Toggle_Addons function.
|
||||
|
||||
'json' : WIP - setitng = method, value = params, see documentation on
|
||||
JSON-RPC API here: http://kodi.wiki/view/JSON-RPC_API)
|
||||
|
||||
setting - This is the name of the setting you want to change, it could be a
|
||||
setting from the kodi settings or a skin based setting. If you're wanting
|
||||
to enable/disable an add-on this is set as the add-on id.
|
||||
|
||||
value: This is the value you want to change the setting to. By default this
|
||||
is set to 'true'.
|
||||
|
||||
|
||||
EXAMPLE CODE:
|
||||
if dialog.yesno('RSS FEEDS','Would you like to enable or disable your RSS feeds?',yeslabel='ENABLE',nolabel='DISABLE'):
|
||||
koding.Set_Setting(setting_type='kodi_setting', setting='lookandfeel.enablerssfeeds', value='true')
|
||||
else:
|
||||
koding.Set_Setting(setting_type='kodi_setting', setting='lookandfeel.enablerssfeeds', value='false')
|
||||
~"""
|
||||
try: import simplejson as json
|
||||
except: import json
|
||||
|
||||
try:
|
||||
|
||||
# If the setting_type is kodi_setting we run the command to set the relevant values in guisettings.xml
|
||||
if setting_type == 'kodi_setting':
|
||||
setting = '"%s"' % setting
|
||||
value = '"%s"' % value
|
||||
|
||||
query = '{"jsonrpc":"2.0", "method":"Settings.SetSettingValue","params":{"setting":%s,"value":%s}, "id":1}' % (setting, value)
|
||||
response = xbmc.executeJSONRPC(query)
|
||||
|
||||
if 'error' in str(response):
|
||||
query = '{"jsonrpc":"2.0", "method":"Settings.SetSettingValue","params":{"setting":%s,"value":%s}, "id":1}' % (setting, value.replace('"',''))
|
||||
response = xbmc.executeJSONRPC(query)
|
||||
if 'error' in str(response):
|
||||
xbmc.log('### Error With Setting: %s' % response, 2)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
|
||||
# Set a skin string to <value>
|
||||
elif setting_type == 'string':
|
||||
xbmc.executebuiltin('Skin.SetString(%s,%s)' % (setting, value))
|
||||
|
||||
# Set a skin setting to true
|
||||
elif setting_type == 'bool_true':
|
||||
xbmc.executebuiltin('Skin.SetBool(%s)' % setting)
|
||||
|
||||
# Set a skin setting to false
|
||||
elif setting_type == 'bool_false':
|
||||
xbmc.executebuiltin('Skin.Reset(%s)' % setting)
|
||||
|
||||
# If we're enabling/disabling an addon
|
||||
elif setting_type == 'addon_enable':
|
||||
if setting != '':
|
||||
query = '{"jsonrpc":"2.0", "method":"Addons.SetAddonEnabled","params":{"addonid":"%s", "enabled":%s}, "id":1}' % (setting, value)
|
||||
response = xbmc.executeJSONRPC(query)
|
||||
if 'error' in str(response):
|
||||
xbmc.log('### Error in json: %s'%query,2)
|
||||
xbmc.log('^ %s' % response, 2)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
# If it's none of the above then it must be a json command so we use the setting_type as the method in json
|
||||
elif setting_type == 'json':
|
||||
query = '{"jsonrpc":"2.0", "method":"%s","params":{%s}, "id":1}' % (setting, value)
|
||||
response = xbmc.executeJSONRPC(query)
|
||||
if 'error' in str(response):
|
||||
xbmc.log('### Error With Setting: %s' % response,2)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
except:
|
||||
xbmc.log(Last_Error())
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Sleep_If_Function_Active(function, args=[], kill_time=30, show_busy=True):
|
||||
"""
|
||||
This will allow you to pause code while a specific function is
|
||||
running in the background.
|
||||
|
||||
CODE: Sleep_If_Function_Active(function, args, kill_time, show_busy)
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
function - This is the function you want to run. This does
|
||||
not require brackets, you only need the function name.
|
||||
|
||||
args - These are the arguments you want to send through to
|
||||
the function, these need to be sent through as a list.
|
||||
|
||||
kill_time - By default this is set to 30. This is the maximum
|
||||
time in seconds you want to wait for a response. If the max.
|
||||
time is reached before the function completes you will get
|
||||
a response of False.
|
||||
|
||||
show_busy - By default this is set to True so you'll get a busy
|
||||
working dialog appear while the function is running. Set to
|
||||
false if you'd rather not have this.
|
||||
|
||||
EXAMPLE CODE:
|
||||
def Open_Test_URL(url):
|
||||
koding.Open_URL(url)
|
||||
|
||||
dialog.ok('SLEEP IF FUNCTION ACTIVE','We will now attempt to read a 20MB zip and then give up after 10 seconds.','Press OK to continue.')
|
||||
koding.Sleep_If_Function_Active(function=Open_Test_URL, args=['http://download.thinkbroadband.com/20MB.zip'], kill_time=10, show_busy=True)
|
||||
dialog.ok('FUNCTION COMPLETE','Of course we cannot read that file in just 10 seconds so we\'ve given up!')
|
||||
~"""
|
||||
from guitools import Show_Busy
|
||||
import threading
|
||||
if show_busy:
|
||||
Show_Busy(True)
|
||||
my_thread = threading.Thread(target=function, args=args)
|
||||
my_thread.start()
|
||||
thread_alive = True
|
||||
counter = 0
|
||||
while thread_alive and counter <= kill_time:
|
||||
xbmc.sleep(1000)
|
||||
thread_alive = my_thread.isAlive()
|
||||
counter += 1
|
||||
if show_busy:
|
||||
Show_Busy(False)
|
||||
return thread_alive
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Sleep_If_Window_Active(window_type=10147):
|
||||
"""
|
||||
This will allow you to pause code while a specific window is open.
|
||||
|
||||
CODE: Sleep_If_Window_Active(window_type)
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
window_type - This is the window xml name you want to check for, if it's
|
||||
active then the code will sleep until it becomes inactive. By default this
|
||||
is set to the custom text box (10147). You can find a list of window ID's
|
||||
here: http://kodi.wiki/view/Window_IDs
|
||||
|
||||
EXAMPLE CODE:
|
||||
koding.Text_Box('EXAMPLE TEXT','This is just an example, normally a text box would not pause code and the next command would automatically run immediately over the top of this.')
|
||||
koding.Sleep_If_Window_Active(10147) # This is the window id for the text box
|
||||
dialog.ok('WINDOW CLOSED','The window has now been closed so this dialog code has now been initiated')
|
||||
~"""
|
||||
from __init__ import dolog
|
||||
windowactive = False
|
||||
counter = 0
|
||||
|
||||
if window_type == 'yesnodialog' or window_type == 10100:
|
||||
count = 30
|
||||
else:
|
||||
count = 10
|
||||
|
||||
okwindow = False
|
||||
|
||||
# Do not get stuck in an infinite loop. Check x amount of times and if condition isn't met after x amount it quits
|
||||
while not okwindow and counter < count:
|
||||
xbmc.sleep(100)
|
||||
okwindow = xbmc.getCondVisibility('Window.IsActive(%s)' % window_type)
|
||||
counter += 1
|
||||
|
||||
# Window is active
|
||||
while okwindow:
|
||||
okwindow = xbmc.getCondVisibility('Window.IsActive(%s)' % window_type)
|
||||
xbmc.sleep(250)
|
||||
|
||||
return okwindow
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def System(command, function=''):
|
||||
"""
|
||||
This is just a simplified method of grabbing certain Kodi infolabels, paths
|
||||
and booleans as well as performing some basic built in kodi functions.
|
||||
We have a number of regularly used functions added to a dictionary which can
|
||||
quickly be called via this function or you can use this function to easily
|
||||
run a command not currently in the dictionary. Just use one of the
|
||||
many infolabels, builtin commands or conditional visibilities available:
|
||||
|
||||
info: http://kodi.wiki/view/InfoLabels
|
||||
bool: http://kodi.wiki/view/List_of_boolean_conditions
|
||||
|
||||
CODE: System(command, [function])
|
||||
|
||||
AVAILABLE PARAMS:
|
||||
|
||||
(*) command - This is the command you want to perform, below is a list
|
||||
of all the default commands you can choose from, however you can of course
|
||||
send through your own custom command if using the function option (details
|
||||
at bottom of page)
|
||||
|
||||
AVAILABLE VALUES:
|
||||
|
||||
'addonid' : Returns the FOLDER id of the current add-on. Please note could differ from real add-on id.
|
||||
'addonname' : Returns the current name of the add-on
|
||||
'builddate' : Return the build date for the current running version of Kodi
|
||||
'cpu' : Returns the CPU usage as a percentage
|
||||
'cputemp' : Returns the CPU temperature in farenheit or celcius depending on system settings
|
||||
'currentlabel' : Returns the current label of the item in focus
|
||||
'currenticon' : Returns the name of the current icon
|
||||
'currentpos' : Returns the current list position of focused item
|
||||
'currentpath' : Returns the url called by Kodi for the focused item
|
||||
'currentrepo' : Returns the repo of the current focused item
|
||||
'currentskin' : Returns the FOLDER id of the skin. Please note could differ from actual add-on id
|
||||
'date' : Returns the date (Tuesday, April 11, 2017)
|
||||
'debug' : Toggles debug mode on/off
|
||||
'freeram' : Returns the amount of free memory available (in MB)
|
||||
'freespace' : Returns amount of free space on storage in this format: 10848 MB Free
|
||||
'hibernate' : Hibernate system, please note not all systems are capable of waking from hibernation
|
||||
'internetstate' : Returns True or False on whether device is connected to internet
|
||||
'ip' : Return the current LOCAL IP address (not your public IP)
|
||||
'kernel' : Return details of the system kernel
|
||||
'language' : Return the language currently in use
|
||||
'mac' : Return the mac address, will only return the mac currently in use (Wi-Fi OR ethernet, not both)
|
||||
'numitems' : Return the total amount of list items curently in focus
|
||||
'profile' : Return the currently running profile name
|
||||
'quit' : Quit Kodi
|
||||
'reboot' : Reboot the system
|
||||
'restart' : Restart Kodi (Windows/Linux only)
|
||||
'shutdown' : Shutdown the system
|
||||
'sortmethod' : Return the current list sort method
|
||||
'sortorder' : Return the current list sort order
|
||||
'systemname' : Return a clean friendly name for the system
|
||||
'time' : Return the current time in this format: 2:05 PM
|
||||
'usedspace' : Return the amount of used space on the storage in this format: 74982 MB Used
|
||||
'version' : Return the current version of Kodi, this may need cleaning up as it contains full file details
|
||||
'viewmode' : Return the current list viewmode
|
||||
'weatheraddon' : Return the current plugin being used for weather
|
||||
|
||||
|
||||
function - This is optional and default is set to a blank string which will
|
||||
allow you to use the commands listed above but if set you can use your own
|
||||
custom commands by setting this to one of the values below.
|
||||
|
||||
AVAILABLE VALUES:
|
||||
|
||||
'bool' : This will allow you to send through a xbmc.getCondVisibility() command
|
||||
'info' : This will allow you to send through a xbmc.getInfoLabel() command
|
||||
'exec' : This will allow you to send through a xbmc.executebuiltin() command
|
||||
|
||||
EXAMPLE CODE:
|
||||
current_time = koding.System(command='time')
|
||||
current_label = koding.System(command='currentlabel')
|
||||
is_folder = koding.System(command='ListItem.IsFolder', function='bool')
|
||||
dialog.ok('PULLED DETAILS','The current time is %s' % current_time, 'Folder status of list item [COLOR=dodgerblue]%s[/COLOR]: %s' % (current_label, is_folder),'^ A zero means False, as in it\'s not a folder.')
|
||||
~"""
|
||||
params = {
|
||||
'addonid' :'xbmc.getInfoLabel("Container.PluginName")',
|
||||
'addonname' :'xbmc.getInfoLabel("Container.FolderName")',
|
||||
'builddate' :'xbmc.getInfoLabel("System.BuildDate")',
|
||||
'cpu' :'xbmc.getInfoLabel("System.CpuUsage")',
|
||||
'cputemp' :'xbmc.getInfoLabel("System.CPUTemperature")',
|
||||
'currentlabel' :'xbmc.getInfoLabel("System.CurrentControl")',
|
||||
'currenticon' :'xbmc.getInfoLabel("ListItem.Icon")',
|
||||
'currentpos' :'xbmc.getInfoLabel("Container.CurrentItem")',
|
||||
'currentpath' :'xbmc.getInfoLabel("Container.FolderPath")',
|
||||
'currentrepo' :'xbmc.getInfoLabel("Container.Property(reponame)")',
|
||||
'currentskin' :'xbmc.getSkinDir()',
|
||||
'date' :'xbmc.getInfoLabel("System.Date")',
|
||||
'debug' :'xbmc.executebuiltin("ToggleDebug")',
|
||||
'freeram' :'xbmc.getFreeMem()',
|
||||
'freespace' :'xbmc.getInfoLabel("System.FreeSpace")',
|
||||
'hibernate' :'xbmc.executebuiltin("Hibernate")',
|
||||
'internetstate' :'xbmc.getInfoLabel("System.InternetState")',
|
||||
'ip' :'xbmc.getIPAddress()',
|
||||
'kernel' :'xbmc.getInfoLabel("System.KernelVersion")',
|
||||
'language' :'xbmc.getInfoLabel("System.Language")',
|
||||
'mac' :'xbmc.getInfoLabel("Network.MacAddress")',
|
||||
'numitems' :'xbmc.getInfoLabel("Container.NumItems")',
|
||||
'profile' :'xbmc.getInfoLabel("System.ProfileName")',
|
||||
'quit' :'xbmc.executebuiltin("Quit")',
|
||||
'reboot' :'xbmc.executebuiltin("Reboot")',
|
||||
'restart' :'xbmc.restart()', # Windows/Linux only
|
||||
'shutdown' :'xbmc.shutdown()',
|
||||
'sortmethod' :'xbmc.getInfoLabel("Container.SortMethod")',
|
||||
'sortorder' :'xbmc.getInfoLabel("Container.SortOrder")',
|
||||
'systemname' :'xbmc.getInfoLabel("System.FriendlyName")',
|
||||
'time' :'xbmc.getInfoLabel("System.Time")',
|
||||
'usedspace' :'xbmc.getInfoLabel("System.UsedSpace")',
|
||||
'version' :'xbmc.getInfoLabel("System.BuildVersion")',
|
||||
'viewmode' :'xbmc.getInfoLabel("Container.Viewmode")',
|
||||
'weatheraddon' :'xbmc.getInfoLabel("Weather.plugin")',
|
||||
}
|
||||
|
||||
if function == '': newcommand = params[command]
|
||||
elif function == 'info': newcommand = 'xbmc.getInfoLabel("%s")' % command
|
||||
elif function == 'bool': newcommand = 'xbmc.getCondVisibility("%s")' % command
|
||||
elif function == 'exec': newcommand = 'xbmc.getCondVisibility("%s")' % command
|
||||
else:
|
||||
dialog.ok('INCORRECT PARAMS','The following command has been called:','koding.System(%s,[COLOR=dodgerblue]%s[/COLOR])'%(command, function),'^ The wrong function has been sent through, please double check the section highlighted in blue.')
|
||||
|
||||
try:
|
||||
return eval(newcommand)
|
||||
except:
|
||||
return 'error'
|
||||
#----------------------------------------------------------------
|
||||
# TUTORIAL #
|
||||
def Timestamp(mode = 'integer'):
|
||||
"""
|
||||
This will return the timestamp in various formats. By default it returns as "integer" mode but other options are listed below:
|
||||
|
||||
CODE: Timestamp(mode)
|
||||
mode is optional, by default it's set as integer
|
||||
|
||||
AVAILABLE VALUES:
|
||||
|
||||
'integer' - An integer which is nice and easy to work with in Python (especially for
|
||||
finding out human readable diffs). The format returned is [year][month][day][hour][minutes][seconds].
|
||||
|
||||
'epoch' - Unix Epoch format (calculated in seconds passed since 12:00 1st Jan 1970).
|
||||
|
||||
'clean' - A clean user friendly time format: Tue Jan 13 10:17:09 2009
|
||||
|
||||
'date_time' - A clean interger style date with time at end: 2017-04-07 10:17:09
|
||||
|
||||
EXAMPLE CODE:
|
||||
integer_time = koding.Timestamp('integer')
|
||||
epoch_time = koding.Timestamp('epoch')
|
||||
clean_time = koding.Timestamp('clean')
|
||||
date_time = koding.Timestamp('date_time')
|
||||
import datetime
|
||||
installedtime = str(datetime.datetime.now())[:-7]
|
||||
dialog.ok('CURRENT TIME','Integer: %s' % integer_time, 'Epoch: %s' % epoch_time, 'Clean: %s' % clean_time)
|
||||
~"""
|
||||
import time
|
||||
import datetime
|
||||
|
||||
now = time.time()
|
||||
try:
|
||||
localtime = time.localtime(now)
|
||||
except:
|
||||
localtime = str(datetime.datetime.now())[:-7]
|
||||
localtime = localtime.replace('-','').replace(':','')
|
||||
if mode == 'date_time':
|
||||
return time.strftime('%Y-%m-%d %H:%M:%S', localtime)
|
||||
if mode == 'integer':
|
||||
return time.strftime('%Y%m%d%H%M%S', localtime)
|
||||
|
||||
if mode == 'clean':
|
||||
return time.asctime(localtime)
|
||||
|
||||
if mode == 'epoch':
|
||||
return now
|
||||
#----------------------------------------------------------------
|
||||
Reference in New Issue
Block a user