2022-03-14 09:10:42 +03:00
|
|
|
import mimetypes
|
|
|
|
import os
|
2015-01-29 13:34:13 +03:00
|
|
|
import socket
|
2022-03-14 09:10:42 +03:00
|
|
|
import urllib.error
|
|
|
|
import urllib.parse
|
|
|
|
import urllib.parse
|
|
|
|
import urllib.request
|
|
|
|
|
2016-03-09 13:29:58 +03:00
|
|
|
import chardet
|
2022-03-14 09:10:42 +03:00
|
|
|
import sys
|
|
|
|
import xbmc
|
|
|
|
|
|
|
|
from .structs import MediaType
|
2015-01-29 13:34:13 +03:00
|
|
|
|
2016-03-12 00:18:11 +03:00
|
|
|
SUBTITLES_FORMATS = ['.aqt', '.gsub', '.jss', '.sub', '.ttxt', '.pjs', '.psb', '.rt', '.smi', '.stl',
|
2022-03-14 09:10:42 +03:00
|
|
|
'.ssf', '.srt', '.ssa', '.ass', '.usf', '.idx']
|
2022-03-25 01:31:20 +03:00
|
|
|
VIDEO_FORMATS = ['.mkv', '.mp4', '.avi', '.ogv', '.ts', '.flv', '.webm', '.vob', '.3gp', '.mpg', '.mpeg']
|
2015-01-29 13:34:13 +03:00
|
|
|
|
2016-03-10 19:55:25 +03:00
|
|
|
class Struct(dict):
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
return self[attr]
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2016-03-10 19:55:25 +03:00
|
|
|
def __setattr__(self, attr, value):
|
|
|
|
self[attr] = value
|
|
|
|
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2022-03-20 00:13:34 +03:00
|
|
|
def uri2path(uri: str) -> str:
|
|
|
|
uri_path: str = ''
|
2016-03-12 02:29:23 +03:00
|
|
|
if uri[1] == ':' and sys.platform.startswith('win'):
|
|
|
|
uri = 'file:///' + uri
|
2022-03-20 00:13:34 +03:00
|
|
|
file_uri = urllib.parse.urlparse(uri)
|
|
|
|
if file_uri.scheme == 'file':
|
|
|
|
uri_path = file_uri.path
|
|
|
|
if uri_path != '' and sys.platform.startswith('win') and (os.path.sep == uri_path[0] or uri_path[0] == '/'):
|
|
|
|
uri_path = uri_path[1:]
|
|
|
|
abs_path = os.path.abspath(urllib.parse.unquote(uri_path))
|
|
|
|
return localize_path(abs_path)
|
2016-03-12 02:29:23 +03:00
|
|
|
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2016-03-12 00:18:11 +03:00
|
|
|
def detect_media_type(name):
|
|
|
|
ext = os.path.splitext(name)[1]
|
|
|
|
if ext in SUBTITLES_FORMATS:
|
|
|
|
return MediaType.SUBTITLES
|
|
|
|
else:
|
|
|
|
mime_type = mimetypes.guess_type(name)[0]
|
2022-03-25 01:31:20 +03:00
|
|
|
if mime_type is None:
|
|
|
|
if ext.lower() in VIDEO_FORMATS:
|
|
|
|
return MediaType.VIDEO
|
2016-03-12 00:18:11 +03:00
|
|
|
return MediaType.UNKNOWN
|
|
|
|
mime_type = mime_type.split("/")[0]
|
|
|
|
if mime_type == 'audio':
|
|
|
|
return MediaType.AUDIO
|
|
|
|
elif mime_type == 'video':
|
|
|
|
return MediaType.VIDEO
|
|
|
|
else:
|
|
|
|
return MediaType.UNKNOWN
|
2022-03-14 09:10:42 +03:00
|
|
|
|
|
|
|
|
2016-03-14 13:29:14 +03:00
|
|
|
def unicode_msg(tmpl, args):
|
2022-03-14 09:10:42 +03:00
|
|
|
msg = isinstance(tmpl, str) and tmpl or tmpl.decode(chardet.detect(tmpl)['encoding'])
|
2016-03-12 02:29:23 +03:00
|
|
|
arg_ = []
|
|
|
|
for a in args:
|
2022-03-14 09:10:42 +03:00
|
|
|
arg_.append(isinstance(a, str) and a or a.decode(chardet.detect(a)['encoding']))
|
2016-03-12 02:29:23 +03:00
|
|
|
return msg % tuple(arg_)
|
2016-03-14 13:29:14 +03:00
|
|
|
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2016-03-14 13:29:14 +03:00
|
|
|
def encode_msg(msg):
|
2022-03-14 09:10:42 +03:00
|
|
|
msg = isinstance(msg, str) and msg.encode(
|
|
|
|
sys.getfilesystemencoding() != 'ascii' and sys.getfilesystemencoding() or 'utf-8') or msg
|
2016-03-14 13:29:14 +03:00
|
|
|
return msg
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2016-03-10 19:55:25 +03:00
|
|
|
|
2016-03-09 13:29:58 +03:00
|
|
|
def localize_path(path):
|
2022-03-14 09:10:42 +03:00
|
|
|
if isinstance(path, bytes):
|
|
|
|
path = path.decode(chardet.detect(path)['encoding'])
|
|
|
|
# if not sys.platform.startswith('win'):
|
|
|
|
# path = path.encode(
|
|
|
|
# (sys.getfilesystemencoding() not in ('ascii', 'ANSI_X3.4-1968')) and sys.getfilesystemencoding() or 'utf-8')
|
2016-03-09 13:29:58 +03:00
|
|
|
return path
|
|
|
|
|
2022-03-14 09:10:42 +03:00
|
|
|
|
2015-01-29 13:34:13 +03:00
|
|
|
def can_bind(host, port):
|
|
|
|
"""
|
|
|
|
Checks we can bind to specified host and port
|
|
|
|
|
|
|
|
:param host: Host
|
|
|
|
:param port: Port
|
|
|
|
:return: True if bind succeed
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
s.bind((host, port))
|
|
|
|
s.close()
|
|
|
|
except socket.error:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def find_free_port(host):
|
|
|
|
"""
|
|
|
|
Finds free TCP port that can be used for binding
|
|
|
|
|
|
|
|
:param host: Host
|
|
|
|
:return: Free port
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
s.bind((host, 0))
|
|
|
|
port = s.getsockname()[1]
|
|
|
|
s.close()
|
|
|
|
except socket.error:
|
|
|
|
return False
|
|
|
|
return port
|
|
|
|
|
|
|
|
|
|
|
|
def ensure_fs_encoding(string):
|
2022-03-14 09:10:42 +03:00
|
|
|
if isinstance(string, bytes):
|
2015-01-29 13:34:13 +03:00
|
|
|
string = string.decode('utf-8')
|
|
|
|
return string.encode(sys.getfilesystemencoding() or 'utf-8')
|
2022-03-20 00:13:34 +03:00
|
|
|
|
|
|
|
|
|
|
|
def get_platform():
|
|
|
|
ret = {
|
|
|
|
"arch": sys.maxsize > 2 ** 32 and "x64" or "x86",
|
|
|
|
}
|
|
|
|
if xbmc.getCondVisibility("system.platform.android"):
|
|
|
|
ret["os"] = "android"
|
|
|
|
if "arm" in os.uname()[4] or "aarch64" in os.uname()[4]:
|
|
|
|
ret["arch"] = "arm"
|
|
|
|
elif xbmc.getCondVisibility("system.platform.linux"):
|
|
|
|
ret["os"] = "linux"
|
|
|
|
uname = os.uname()[4]
|
|
|
|
if "arm" in uname:
|
|
|
|
if "armv7" in uname:
|
|
|
|
ret["arch"] = "armv7"
|
|
|
|
else:
|
|
|
|
ret["arch"] = "armv6"
|
|
|
|
elif "mips" in uname:
|
|
|
|
ret["arch"] = 'mipsel'
|
|
|
|
elif "aarch64" in uname:
|
|
|
|
if sys.maxsize > 2147483647: # is_64bit_system
|
|
|
|
ret["arch"] = 'aarch64'
|
|
|
|
else:
|
|
|
|
ret["arch"] = "armv7" # 32-bit userspace
|
|
|
|
elif xbmc.getCondVisibility("system.platform.windows"):
|
|
|
|
ret["os"] = "windows"
|
|
|
|
elif xbmc.getCondVisibility("system.platform.osx"):
|
|
|
|
ret["os"] = "darwin"
|
|
|
|
elif xbmc.getCondVisibility("system.platform.ios"):
|
|
|
|
ret["os"] = "ios"
|
|
|
|
ret["arch"] = "arm"
|
|
|
|
|
|
|
|
ret = get_system(ret)
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
def get_system(ret):
|
|
|
|
ret["system"] = ''
|
|
|
|
if ret["os"] == 'windows':
|
|
|
|
ret["system"] = 'windows_' + ret['arch']
|
|
|
|
elif ret["os"] == "linux" and ret["arch"] == "x64":
|
|
|
|
ret["system"] = 'linux_x86_64'
|
|
|
|
elif ret["os"] == "linux" and ret["arch"] == "x86":
|
|
|
|
ret["system"] = 'linux_x86'
|
|
|
|
elif ret["os"] == "linux" and "aarch64" in ret["arch"]:
|
|
|
|
ret["system"] = 'linux_' + ret["arch"]
|
|
|
|
elif ret["os"] == "linux" and ("arm" in ret["arch"] or 'mips' in ret["arch"]):
|
|
|
|
ret["system"] = 'linux_' + ret["arch"]
|
|
|
|
elif ret["os"] == "android":
|
|
|
|
if ret["arch"] == 'arm':
|
|
|
|
ret["system"] = 'android_armv7'
|
|
|
|
else:
|
|
|
|
ret["system"] = 'android_x86'
|
|
|
|
elif ret["os"] == "darwin":
|
|
|
|
ret["system"] = 'darwin'
|
|
|
|
elif ret["os"] == "ios" and ret["arch"] == "arm":
|
|
|
|
ret["system"] = 'ios_arm'
|
|
|
|
return ret
|