# -*- coding: utf-8 -*-
"""
Burst utilities
"""
import os
import re
import xbmc
import xbmcgui
import xbmcaddon
from elementum.provider import get_setting
from providers.definitions import definitions
from urlparse import urlparse
ADDON = xbmcaddon.Addon()
ADDON_ID = ADDON.getAddonInfo("id")
ADDON_NAME = ADDON.getAddonInfo("name")
ADDON_PATH = ADDON.getAddonInfo("path").decode('utf-8')
ADDON_ICON = ADDON.getAddonInfo("icon").decode('utf-8')
ADDON_PROFILE = ADDON.getAddonInfo("profile")
ADDON_VERSION = ADDON.getAddonInfo("version")
PATH_ADDONS = xbmc.translatePath("special://home/addons/")
PATH_TEMP = xbmc.translatePath("special://temp")
if not ADDON_PATH:
ADDON_PATH = '..'
[docs]class Magnet:
""" Magnet link parsing class
Args:
magnet (str): A magnet link string
Attributes:
info_hash (str): Info-hash from the magnet link
name (str): Name of torrent
trackers (list): List of trackers in magnet link
"""
def __init__(self, magnet):
self.magnet = magnet + '&'
info_hash = re.search('urn:btih:(\w+)&', self.magnet, re.IGNORECASE)
self.info_hash = None
if info_hash:
self.info_hash = info_hash.group(1)
name = re.search('dn=(.*?)&', self.magnet)
self.name = None
if name:
self.name = name.group(1).replace('+', ' ').title()
self.trackers = re.findall('tr=(.*?)&', self.magnet)
[docs]def get_domain(url):
if "//" not in url:
url = "http://" + url
parsed_uri = urlparse(url)
domain = '{uri.netloc}'.format(uri=parsed_uri)
return domain
[docs]def get_alias(definition, alias):
definition["alias"] = ""
if alias:
old_domain = ""
for k in ["root_url", "base_url"]:
domain = get_domain(definition[k])
if domain:
old_domain = domain
break
new_domain = get_domain(alias)
if old_domain and new_domain:
definition["alias"] = new_domain
definition["old_domain"] = old_domain
# Substitue all ocurrences of old domain name and replace with new one
for k in definition:
if isinstance(definition[k], basestring):
definition[k] = definition[k].replace(old_domain, new_domain)
for k in definition["parser"]:
if isinstance(definition["parser"][k], basestring):
definition["parser"][k] = definition["parser"][k].replace(old_domain, new_domain)
return definition
[docs]def get_providers():
""" Utility method to get all provider IDs available in the definitions
Returns:
list: All available provider IDs
"""
results = []
for provider in definitions:
results.append(provider)
return results
[docs]def get_enabled_providers():
""" Utility method to get all enabled provider IDs
Returns:
list: All available enabled provider IDs
"""
results = []
for provider in definitions:
if get_setting('use_%s' % provider, bool):
results.append(provider)
if 'custom' in definitions[provider] and definitions[provider]['custom']:
results.append(provider)
return results
[docs]def get_icon_path():
""" Utility method to Burst's icon path
Returns:
str: Path to Burst's icon
"""
return os.path.join(ADDON_PATH, 'icon.png')
[docs]def translation(id_value):
""" Utility method to get translations
Args:
id_value (int): Code of translation to get
Returns:
str: Translated string
"""
return ADDON.getLocalizedString(id_value)
[docs]def get_int(string):
""" Utility method to convert a number contained in a string to an integer
Args:
string (str): Number contained in a string
Returns:
int: The number as an integer, or 0
"""
if not string:
return 0
try:
return int(string)
except:
try:
return int(get_float(string))
except:
pass
try:
return int(filter(type(string).isdigit, string))
except:
return 0
[docs]def get_float(string):
""" Utility method to convert a number contained in a string to a float
Args:
string (str): Number contained in a string
Returns:
float: The number as a float, or 0.0
"""
if not string:
return float(0)
try:
return float(string)
except:
try:
cleaned = clean_number(string)
floated = re.findall(r'[\d.]+', cleaned)[0]
return float(floated)
except:
pass
try:
string = string[:clean_number(string).find('.')]
return float(filter(type(string).isdigit, string))
except:
pass
try:
return float(filter(type(string).isdigit, string))
except:
return float(0)
[docs]def size_int(size_txt):
""" Utility method to convert a file size contained in a string to an integer of bytes
Args:
string (str): File size with suffix contained in a string, eg. ``1.21 GB``
Returns:
float: The number of bytes as a float, or 0.0
"""
try:
return float(size_txt)
except:
try:
size_txt = size_txt.upper()
size = get_float(size_txt)
if 'K' in size_txt:
size *= 1e3
if 'M' in size_txt:
size *= 1e6
if 'G' in size_txt:
size *= 1e9
if 'T' in size_txt:
size *= 1e12
return size
except:
pass
return 0
[docs]def clean_number(string):
""" Utility method to clean up a number contained in a string to dot decimal format
Args:
string (str): Number contained in a string
Returns:
str: The formatted number as a string
"""
comma = string.find(',')
point = string.find('.')
if comma > 0 and point > 0:
if comma < point:
string = string.replace(',', '')
else:
string = string.replace('.', '')
string = string.replace(',', '.')
elif comma > 0:
string = string.replace(',', '.')
return string
[docs]def clean_size(string):
""" Utility method to remove unnecessary information from a file size string, eg. '6.5 GBytes' -> '6.5 GB'
Args:
string (str): File size string to clean up
Returns:
str: Cleaned up file size
"""
if string:
pos = string.rfind('B')
if pos > 0:
string = string[:pos] + 'B'
return string
[docs]def sizeof(num, suffix='B'):
""" Utility method to convert a file size in bytes to a human-readable format
Args:
num (int): Number of bytes
suffix (str): Suffix for 'bytes'
Returns:
str: The formatted file size as a string, eg. ``1.21 GB``
"""
for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1024.0:
return "%3.1f %s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f %s%s" % (num, 'Y', suffix)
[docs]def notify(message, image=None):
""" Creates a notification dialog
Args:
message (str): The message to show in the dialog
image (str): Path to an icon for this dialog
"""
dialog = xbmcgui.Dialog()
dialog.notification(ADDON_NAME, message, icon=image, sound=False)
del dialog
[docs]def clear_cache():
""" Clears cookies from Burst's cache
"""
cookies_path = os.path.join(xbmc.translatePath("special://temp"), "burst")
if os.path.isdir(cookies_path):
for f in os.listdir(cookies_path):
if re.search('.jar', f):
os.remove(os.path.join(cookies_path, f))
[docs]def encode_dict(dict_in):
""" Encodes dict values to UTF-8
Args:
dict_in (dict): Input dictionary with unicode values
Returns:
dict: Output dictionary with UTF-8 encoded values
"""
dict_out = {}
for k, v in dict_in.iteritems():
if isinstance(v, unicode):
v = v.encode('utf8')
elif isinstance(v, str):
v.decode('utf8')
dict_out[k] = v
return dict_out
[docs]def iri2uri(iri):
iri = "".join([encode(c) for c in iri])
return iri
[docs]def encode(c):
retval = c
i = ord(c)
for low, high in escape_range:
if i < low:
break
if i >= low and i <= high:
retval = "".join(["%%%2X" % ord(o) for o in c.encode('cp1251')])
break
return retval
escape_range = [
(0xA0, 0xD7FF),
(0xE000, 0xF8FF),
(0xF900, 0xFDCF),
(0xFDF0, 0xFFEF),
(0x10000, 0x1FFFD),
(0x20000, 0x2FFFD),
(0x30000, 0x3FFFD),
(0x40000, 0x4FFFD),
(0x50000, 0x5FFFD),
(0x60000, 0x6FFFD),
(0x70000, 0x7FFFD),
(0x80000, 0x8FFFD),
(0x90000, 0x9FFFD),
(0xA0000, 0xAFFFD),
(0xB0000, 0xBFFFD),
(0xC0000, 0xCFFFD),
(0xD0000, 0xDFFFD),
(0xE1000, 0xEFFFD),
(0xF0000, 0xFFFFD),
(0x100000, 0x10FFFD),
]