Test Installazione Widevine
This commit is contained in:
@@ -216,12 +216,14 @@ def downloadbest(video_urls, title, continuar=False):
|
|||||||
return -2
|
return -2
|
||||||
|
|
||||||
|
|
||||||
def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False, resumir=True):
|
def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False, resumir=True, header=''):
|
||||||
logger.info("url= " + url)
|
logger.info("url= " + url)
|
||||||
logger.info("filename= " + nombrefichero)
|
logger.info("filename= " + nombrefichero)
|
||||||
|
|
||||||
if headers is None:
|
if headers is None:
|
||||||
headers = []
|
headers = []
|
||||||
|
if not header:
|
||||||
|
header = "plugin"
|
||||||
|
|
||||||
progreso = None
|
progreso = None
|
||||||
|
|
||||||
@@ -269,7 +271,7 @@ def downloadfile(url, nombrefichero, headers=None, silent=False, continuar=False
|
|||||||
|
|
||||||
# Create the progress dialog
|
# Create the progress dialog
|
||||||
if not silent:
|
if not silent:
|
||||||
progreso = platformtools.dialog_progress("plugin", "Downloading...", url, nombrefichero)
|
progreso = platformtools.dialog_progress(header, "Downloading...", url, nombrefichero)
|
||||||
|
|
||||||
# If the platform does not return a valid dialog box, it assumes silent mode
|
# If the platform does not return a valid dialog box, it assumes silent mode
|
||||||
if progreso is None:
|
if progreso is None:
|
||||||
|
|||||||
@@ -0,0 +1,333 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# MIT License (see LICENSE.txt or https://opensource.org/licenses/MIT)
|
||||||
|
# From inputstreamhelper
|
||||||
|
"""Implements a class with methods related to the Chrome OS image"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
import os
|
||||||
|
from struct import calcsize, unpack
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from io import UnsupportedOperation
|
||||||
|
from platformcode import logger, config
|
||||||
|
|
||||||
|
def compat_path(path, encoding='utf-8', errors='strict'):
|
||||||
|
"""Convert unicode path to bytestring if needed"""
|
||||||
|
import sys
|
||||||
|
if (sys.version_info.major == 2 and isinstance(path, unicode) # noqa: F821; pylint: disable=undefined-variable,useless-suppression
|
||||||
|
and not sys.platform.startswith('win')):
|
||||||
|
return path.encode(encoding, errors)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
class ChromeOSImage:
|
||||||
|
"""
|
||||||
|
The main class handling a Chrome OS image
|
||||||
|
|
||||||
|
Information related to ext2 is sourced from here: https://www.nongnu.org/ext2-doc/ext2.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, imgpath):
|
||||||
|
logger.info('Image Path: ' + imgpath)
|
||||||
|
"""Prepares the image"""
|
||||||
|
self.imgpath = imgpath
|
||||||
|
self.bstream = self.get_bstream(imgpath)
|
||||||
|
self.part_offset = None
|
||||||
|
self.sb_dict = None
|
||||||
|
self.blocksize = None
|
||||||
|
self.blk_groups = None
|
||||||
|
self.progress = None
|
||||||
|
|
||||||
|
def gpt_header(self):
|
||||||
|
"""Returns the needed parts of the GPT header, can be easily expanded if necessary"""
|
||||||
|
header_fmt = '<8s4sII4x4Q16sQ3I'
|
||||||
|
header_size = calcsize(header_fmt)
|
||||||
|
lba_size = 512 # assuming LBA size
|
||||||
|
self.seek_stream(lba_size)
|
||||||
|
|
||||||
|
# GPT Header entries: signature, revision, header_size, header_crc32, (reserved 4x skipped,) current_lba, backup_lba,
|
||||||
|
# first_usable_lba, last_usable_lba, disk_guid, start_lba_part_entries, num_part_entries,
|
||||||
|
# size_part_entry, crc32_part_entries
|
||||||
|
_, _, _, _, _, _, _, _, _, start_lba_part_entries, num_part_entries, size_part_entry, _ = unpack(header_fmt, self.read_stream(header_size))
|
||||||
|
|
||||||
|
return (start_lba_part_entries, num_part_entries, size_part_entry)
|
||||||
|
|
||||||
|
def chromeos_offset(self):
|
||||||
|
"""Calculate the Chrome OS losetup start offset"""
|
||||||
|
part_format = '<16s16sQQQ72s'
|
||||||
|
entries_start, entries_num, entry_size = self.gpt_header() # assuming partition table is GPT
|
||||||
|
lba_size = 512 # assuming LBA size
|
||||||
|
self.seek_stream(entries_start * lba_size)
|
||||||
|
|
||||||
|
if not calcsize(part_format) == entry_size:
|
||||||
|
logger.info('Partition table entries are not 128 bytes long')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for index in range(1, entries_num + 1): # pylint: disable=unused-variable
|
||||||
|
# Entry: type_guid, unique_guid, first_lba, last_lba, attr_flags, part_name
|
||||||
|
_, _, first_lba, _, _, part_name = unpack(part_format, self.read_stream(entry_size))
|
||||||
|
part_name = part_name.decode('utf-16').strip('\x00')
|
||||||
|
if part_name == 'ROOT-A': # assuming partition name is ROOT-A
|
||||||
|
offset = first_lba * lba_size
|
||||||
|
break
|
||||||
|
|
||||||
|
if not offset:
|
||||||
|
logger.info('Failed to calculate losetup offset.')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return offset
|
||||||
|
|
||||||
|
def extract_file(self, filename, extract_path, progress):
|
||||||
|
"""Extracts the file from the image"""
|
||||||
|
self.progress = progress
|
||||||
|
|
||||||
|
self.progress.update(2, config.get_localized_string(70813))
|
||||||
|
self.part_offset = self.chromeos_offset()
|
||||||
|
self.sb_dict = self.superblock()
|
||||||
|
self.blk_groups = self.block_groups()
|
||||||
|
|
||||||
|
bin_filename = filename.encode('ascii')
|
||||||
|
chunksize = 4 * 1024**2
|
||||||
|
percent8 = 40
|
||||||
|
self.progress.update(int(percent8 / 8), config.get_localized_string(70814))
|
||||||
|
chunk1 = self.read_stream(chunksize)
|
||||||
|
while True:
|
||||||
|
chunk2 = self.read_stream(chunksize)
|
||||||
|
if not chunk2:
|
||||||
|
logger.info('File %s not found in the ChromeOS image' % filename)
|
||||||
|
return False
|
||||||
|
|
||||||
|
chunk = chunk1 + chunk2
|
||||||
|
if bin_filename in chunk:
|
||||||
|
i_index_pos = chunk.index(bin_filename) - 8
|
||||||
|
dir_dict = self.dir_entry(chunk[i_index_pos:i_index_pos + len(filename) + 8])
|
||||||
|
if dir_dict['inode'] < self.sb_dict['s_inodes_count'] and dir_dict['name_len'] == len(filename):
|
||||||
|
break
|
||||||
|
chunk1 = chunk2
|
||||||
|
if percent8 < 240:
|
||||||
|
percent8 += 1
|
||||||
|
self.progress.update(int(percent8 / 8))
|
||||||
|
|
||||||
|
self.progress.update(32, config.get_localized_string(70815))
|
||||||
|
|
||||||
|
blk_group_num = (dir_dict['inode'] - 1) // self.sb_dict['s_inodes_per_group']
|
||||||
|
blk_group = self.blk_groups[blk_group_num]
|
||||||
|
i_index_in_group = (dir_dict['inode'] - 1) % self.sb_dict['s_inodes_per_group']
|
||||||
|
|
||||||
|
inode_pos = self.part_offset + self.blocksize * blk_group['bg_inode_table'] + self.sb_dict['s_inode_size'] * i_index_in_group
|
||||||
|
inode_dict, _ = self.inode_table(inode_pos)
|
||||||
|
|
||||||
|
return self.write_file(inode_dict, os.path.join(extract_path, filename))
|
||||||
|
|
||||||
|
def superblock(self):
|
||||||
|
"""Get relevant info from the superblock, assert it's an ext2 fs"""
|
||||||
|
names = ('s_inodes_count', 's_blocks_count', 's_r_blocks_count', 's_free_blocks_count', 's_free_inodes_count', 's_first_data_block',
|
||||||
|
's_log_block_size', 's_log_frag_size', 's_blocks_per_group', 's_frags_per_group', 's_inodes_per_group', 's_mtime', 's_wtime',
|
||||||
|
's_mnt_count', 's_max_mnt_count', 's_magic', 's_state', 's_errors', 's_minor_rev_level', 's_lastcheck', 's_checkinterval',
|
||||||
|
's_creator_os', 's_rev_level', 's_def_resuid', 's_def_resgid', 's_first_ino', 's_inode_size', 's_block_group_nr',
|
||||||
|
's_feature_compat', 's_feature_incompat', 's_feature_ro_compat', 's_uuid', 's_volume_name', 's_last_mounted',
|
||||||
|
's_algorithm_usage_bitmap', 's_prealloc_block', 's_prealloc_dir_blocks')
|
||||||
|
fmt = '<13I6H4I2HI2H3I16s16s64sI2B818x'
|
||||||
|
fmt_len = calcsize(fmt)
|
||||||
|
|
||||||
|
self.seek_stream(self.part_offset + 1024) # superblock starts after 1024 byte
|
||||||
|
pack = self.read_stream(fmt_len)
|
||||||
|
sb_dict = dict(zip(names, unpack(fmt, pack)))
|
||||||
|
|
||||||
|
sb_dict['s_magic'] = hex(sb_dict['s_magic'])
|
||||||
|
assert sb_dict['s_magic'] == '0xef53' # assuming/checking this is an ext2 fs
|
||||||
|
|
||||||
|
block_groups_count1 = sb_dict['s_blocks_count'] / sb_dict['s_blocks_per_group']
|
||||||
|
block_groups_count1 = int(block_groups_count1) if float(int(block_groups_count1)) == block_groups_count1 else int(block_groups_count1) + 1
|
||||||
|
block_groups_count2 = sb_dict['s_inodes_count'] / sb_dict['s_inodes_per_group']
|
||||||
|
block_groups_count2 = int(block_groups_count2) if float(int(block_groups_count2)) == block_groups_count2 else int(block_groups_count2) + 1
|
||||||
|
assert block_groups_count1 == block_groups_count2
|
||||||
|
sb_dict['block_groups_count'] = block_groups_count1
|
||||||
|
|
||||||
|
self.blocksize = 1024 << sb_dict['s_log_block_size']
|
||||||
|
|
||||||
|
return sb_dict
|
||||||
|
|
||||||
|
def block_group(self):
|
||||||
|
"""Get info about a block group"""
|
||||||
|
names = ('bg_block_bitmap', 'bg_inode_bitmap', 'bg_inode_table', 'bg_free_blocks_count', 'bg_free_inodes_count', 'bg_used_dirs_count', 'bg_pad')
|
||||||
|
fmt = '<3I4H12x'
|
||||||
|
fmt_len = calcsize(fmt)
|
||||||
|
|
||||||
|
pack = self.read_stream(fmt_len)
|
||||||
|
blk = unpack(fmt, pack)
|
||||||
|
|
||||||
|
blk_dict = dict(zip(names, blk))
|
||||||
|
|
||||||
|
return blk_dict
|
||||||
|
|
||||||
|
def block_groups(self):
|
||||||
|
"""Get info about all block groups"""
|
||||||
|
if self.blocksize == 1024:
|
||||||
|
self.seek_stream(self.part_offset + 2 * self.blocksize)
|
||||||
|
else:
|
||||||
|
self.seek_stream(self.part_offset + self.blocksize)
|
||||||
|
|
||||||
|
blk_groups = []
|
||||||
|
for i in range(self.sb_dict['block_groups_count']): # pylint: disable=unused-variable
|
||||||
|
blk_group = self.block_group()
|
||||||
|
blk_groups.append(blk_group)
|
||||||
|
|
||||||
|
return blk_groups
|
||||||
|
|
||||||
|
def inode_table(self, inode_pos):
|
||||||
|
"""Reads and returns an inode table and inode size"""
|
||||||
|
names = ('i_mode', 'i_uid', 'i_size', 'i_atime', 'i_ctime', 'i_mtime', 'i_dtime', 'i_gid', 'i_links_count', 'i_blocks', 'i_flags',
|
||||||
|
'i_osd1', 'i_block0', 'i_block1', 'i_block2', 'i_block3', 'i_block4', 'i_block5', 'i_block6', 'i_block7', 'i_block8',
|
||||||
|
'i_block9', 'i_block10', 'i_block11', 'i_blocki', 'i_blockii', 'i_blockiii', 'i_generation', 'i_file_acl', 'i_dir_acl', 'i_faddr')
|
||||||
|
fmt = '<2Hi4I2H3I15I4I12x'
|
||||||
|
fmt_len = calcsize(fmt)
|
||||||
|
inode_size = self.sb_dict['s_inode_size']
|
||||||
|
|
||||||
|
self.seek_stream(inode_pos)
|
||||||
|
pack = self.read_stream(fmt_len)
|
||||||
|
inode = unpack(fmt, pack)
|
||||||
|
|
||||||
|
inode_dict = dict(zip(names, inode))
|
||||||
|
inode_dict['i_mode'] = hex(inode_dict['i_mode'])
|
||||||
|
|
||||||
|
blocks = inode_dict['i_size'] / self.blocksize
|
||||||
|
inode_dict['blocks'] = int(blocks) if float(int(blocks)) == blocks else int(blocks) + 1
|
||||||
|
|
||||||
|
self.read_stream(inode_size - fmt_len)
|
||||||
|
return inode_dict, inode_size
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def dir_entry(chunk):
|
||||||
|
"""Returns the directory entry found in chunk"""
|
||||||
|
dir_names = ('inode', 'rec_len', 'name_len', 'file_type', 'name')
|
||||||
|
dir_fmt = '<IHBB' + str(len(chunk) - 8) + 's'
|
||||||
|
|
||||||
|
dir_dict = dict(zip(dir_names, unpack(dir_fmt, chunk)))
|
||||||
|
|
||||||
|
return dir_dict
|
||||||
|
|
||||||
|
def iblock_ids(self, blk_id, ids_to_read):
|
||||||
|
"""Reads the block indices/IDs from an indirect block"""
|
||||||
|
seek_pos = self.part_offset + self.blocksize * blk_id
|
||||||
|
self.seek_stream(seek_pos)
|
||||||
|
fmt = '<' + str(int(self.blocksize / 4)) + 'I'
|
||||||
|
ids = list(unpack(fmt, self.read_stream(self.blocksize)))
|
||||||
|
ids_to_read -= len(ids)
|
||||||
|
|
||||||
|
return ids, ids_to_read
|
||||||
|
|
||||||
|
def iiblock_ids(self, blk_id, ids_to_read):
|
||||||
|
"""Reads the block indices/IDs from a doubly-indirect block"""
|
||||||
|
seek_pos = self.part_offset + self.blocksize * blk_id
|
||||||
|
self.seek_stream(seek_pos)
|
||||||
|
fmt = '<' + str(int(self.blocksize / 4)) + 'I'
|
||||||
|
iids = unpack(fmt, self.read_stream(self.blocksize))
|
||||||
|
|
||||||
|
ids = []
|
||||||
|
for iid in iids:
|
||||||
|
if ids_to_read <= 0:
|
||||||
|
break
|
||||||
|
ind_block_ids, ids_to_read = self.iblock_ids(iid, ids_to_read)
|
||||||
|
ids += ind_block_ids
|
||||||
|
|
||||||
|
return ids, ids_to_read
|
||||||
|
|
||||||
|
def seek_stream(self, seek_pos):
|
||||||
|
"""Move position of bstream to seek_pos"""
|
||||||
|
try:
|
||||||
|
self.bstream[0].seek(seek_pos)
|
||||||
|
self.bstream[1] = seek_pos
|
||||||
|
return
|
||||||
|
|
||||||
|
except UnsupportedOperation:
|
||||||
|
chunksize = 4 * 1024**2
|
||||||
|
|
||||||
|
if seek_pos >= self.bstream[1]:
|
||||||
|
while seek_pos - self.bstream[1] > chunksize:
|
||||||
|
self.read_stream(chunksize)
|
||||||
|
self.read_stream(seek_pos - self.bstream[1])
|
||||||
|
return
|
||||||
|
|
||||||
|
self.bstream[0].close()
|
||||||
|
self.bstream[1] = 0
|
||||||
|
self.bstream = self.get_bstream(self.imgpath)
|
||||||
|
|
||||||
|
while seek_pos - self.bstream[1] > chunksize:
|
||||||
|
self.read_stream(chunksize)
|
||||||
|
self.read_stream(seek_pos - self.bstream[1])
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def read_stream(self, num_of_bytes):
|
||||||
|
"""Read and return a chunk of the bytestream"""
|
||||||
|
self.bstream[1] += num_of_bytes
|
||||||
|
|
||||||
|
return self.bstream[0].read(num_of_bytes)
|
||||||
|
|
||||||
|
def get_block_ids(self, inode_dict):
|
||||||
|
"""Get all block indices/IDs of an inode"""
|
||||||
|
ids_to_read = inode_dict['blocks']
|
||||||
|
block_ids = [inode_dict['i_block' + str(i)] for i in range(12)]
|
||||||
|
ids_to_read -= 12
|
||||||
|
|
||||||
|
if not inode_dict['i_blocki'] == 0:
|
||||||
|
iblocks, ids_to_read = self.iblock_ids(inode_dict['i_blocki'], ids_to_read)
|
||||||
|
block_ids += iblocks
|
||||||
|
if not inode_dict['i_blockii'] == 0:
|
||||||
|
iiblocks, ids_to_read = self.iiblock_ids(inode_dict['i_blockii'], ids_to_read)
|
||||||
|
block_ids += iiblocks
|
||||||
|
|
||||||
|
return block_ids[:inode_dict['blocks']]
|
||||||
|
|
||||||
|
def read_file(self, block_ids):
|
||||||
|
"""Read blocks specified by IDs into a dict"""
|
||||||
|
block_dict = {}
|
||||||
|
for block_id in block_ids:
|
||||||
|
percent = int(35 + 60 * block_ids.index(block_id) / len(block_ids))
|
||||||
|
self.progress.update(percent, config.get_localized_string(70816))
|
||||||
|
seek_pos = self.part_offset + self.blocksize * block_id
|
||||||
|
self.seek_stream(seek_pos)
|
||||||
|
block_dict[block_id] = self.read_stream(self.blocksize)
|
||||||
|
|
||||||
|
return block_dict
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def write_file_chunk(opened_file, chunk, bytes_to_write):
|
||||||
|
"""Writes bytes to file in chunks"""
|
||||||
|
if len(chunk) > bytes_to_write:
|
||||||
|
opened_file.write(chunk[:bytes_to_write])
|
||||||
|
return 0
|
||||||
|
|
||||||
|
opened_file.write(chunk)
|
||||||
|
return bytes_to_write - len(chunk)
|
||||||
|
|
||||||
|
def write_file(self, inode_dict, filepath):
|
||||||
|
"""Writes file specified by its inode to filepath"""
|
||||||
|
bytes_to_write = inode_dict['i_size']
|
||||||
|
block_ids = self.get_block_ids(inode_dict)
|
||||||
|
|
||||||
|
block_ids_sorted = block_ids[:]
|
||||||
|
block_ids_sorted.sort()
|
||||||
|
block_dict = self.read_file(block_ids_sorted)
|
||||||
|
|
||||||
|
write_dir = os.path.join(os.path.dirname(filepath), '')
|
||||||
|
if not os.path.exists(write_dir):
|
||||||
|
os.mkdir(write_dir)
|
||||||
|
|
||||||
|
with open(compat_path(filepath), 'wb') as opened_file:
|
||||||
|
for block_id in block_ids:
|
||||||
|
bytes_to_write = self.write_file_chunk(opened_file, block_dict[block_id], bytes_to_write)
|
||||||
|
if bytes_to_write == 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_bstream(imgpath):
|
||||||
|
"""Get a bytestream of the image"""
|
||||||
|
if imgpath.endswith('.zip'):
|
||||||
|
bstream = ZipFile(imgpath, 'r').open(os.path.basename(imgpath).strip('.zip'), 'r')
|
||||||
|
else:
|
||||||
|
bstream = open(imgpath, 'rb')
|
||||||
|
|
||||||
|
return [bstream, 0]
|
||||||
@@ -248,7 +248,7 @@ def getCurrentView(item=None, parent_item=None):
|
|||||||
elif (item.contentType in ['movie'] and parent_item.action in parent_actions) \
|
elif (item.contentType in ['movie'] and parent_item.action in parent_actions) \
|
||||||
or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']) \
|
or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']) \
|
||||||
or (parent_item.channel in ['favorites'] and parent_item.action in ['mainlist']) \
|
or (parent_item.channel in ['favorites'] and parent_item.action in ['mainlist']) \
|
||||||
or parent_item.action in ['now_on_tv', 'now_on_misc', 'now_on_misc_film', 'mostrar_perfil', 'live']:
|
or parent_item.action in ['now_on_tv', 'now_on_misc', 'now_on_misc_film', 'mostrar_perfil', 'live', 'replay']:
|
||||||
return 'movie', 'movies'
|
return 'movie', 'movies'
|
||||||
|
|
||||||
elif (item.contentType in ['tvshow'] and parent_item.action in parent_actions) \
|
elif (item.contentType in ['tvshow'] and parent_item.action in parent_actions) \
|
||||||
@@ -505,7 +505,7 @@ def is_playing():
|
|||||||
|
|
||||||
def play_video(item, strm=False, force_direct=False, autoplay=False):
|
def play_video(item, strm=False, force_direct=False, autoplay=False):
|
||||||
logger.info()
|
logger.info()
|
||||||
# logger.debug(item.tostring('\n'))
|
logger.debug(item.tostring('\n'))
|
||||||
if item.channel == 'downloads':
|
if item.channel == 'downloads':
|
||||||
logger.info("Play local video: %s [%s]" % (item.title, item.url))
|
logger.info("Play local video: %s [%s]" % (item.title, item.url))
|
||||||
xlistitem = xbmcgui.ListItem(path=item.url)
|
xlistitem = xbmcgui.ListItem(path=item.url)
|
||||||
@@ -548,6 +548,11 @@ def play_video(item, strm=False, force_direct=False, autoplay=False):
|
|||||||
install_inputstream()
|
install_inputstream()
|
||||||
xlistitem.setProperty('inputstreamaddon', 'inputstream.adaptive')
|
xlistitem.setProperty('inputstreamaddon', 'inputstream.adaptive')
|
||||||
xlistitem.setProperty('inputstream.adaptive.manifest_type', 'mpd')
|
xlistitem.setProperty('inputstream.adaptive.manifest_type', 'mpd')
|
||||||
|
if item.drm and item.license:
|
||||||
|
install_widevine()
|
||||||
|
xlistitem.setProperty("inputstream.adaptive.license_type", item.drm)
|
||||||
|
xlistitem.setProperty("inputstream.adaptive.license_key", item.license)
|
||||||
|
xlistitem.setMimeType('application/dash+xml')
|
||||||
|
|
||||||
if force_direct: item.play_from = 'window'
|
if force_direct: item.play_from = 'window'
|
||||||
|
|
||||||
@@ -1067,6 +1072,9 @@ def resume_playback(item, return_played_time=False):
|
|||||||
item.nfo = item.strm_path = ""
|
item.nfo = item.strm_path = ""
|
||||||
return item, None, None, None
|
return item, None, None, None
|
||||||
|
|
||||||
|
|
||||||
|
##### INPUTSTREM #####
|
||||||
|
|
||||||
def install_inputstream():
|
def install_inputstream():
|
||||||
from xbmcaddon import Addon
|
from xbmcaddon import Addon
|
||||||
if not os.path.exists(os.path.join(xbmc.translatePath('special://home/addons/'),'inputstream.adaptive')) and not os.path.exists(os.path.join(xbmc.translatePath('special://xbmcbinaddons/'),'inputstream.adaptive')):
|
if not os.path.exists(os.path.join(xbmc.translatePath('special://home/addons/'),'inputstream.adaptive')) and not os.path.exists(os.path.join(xbmc.translatePath('special://xbmcbinaddons/'),'inputstream.adaptive')):
|
||||||
@@ -1086,3 +1094,174 @@ def install_inputstream():
|
|||||||
except:
|
except:
|
||||||
xbmc.executebuiltin('UpdateLocalAddons')
|
xbmc.executebuiltin('UpdateLocalAddons')
|
||||||
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "inputstream.adaptive", "enabled": true }}')
|
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "inputstream.adaptive", "enabled": true }}')
|
||||||
|
|
||||||
|
|
||||||
|
def install_widevine():
|
||||||
|
platform = get_platform()
|
||||||
|
if platform['os'] != 'android':
|
||||||
|
from core.httptools import downloadpage
|
||||||
|
from xbmcaddon import Addon
|
||||||
|
from core import jsontools
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
path = xbmc.translatePath(Addon('inputstream.adaptive').getSetting('DECRYPTERPATH'))
|
||||||
|
|
||||||
|
# if Widevine CDM is not installed
|
||||||
|
if not os.path.exists(path):
|
||||||
|
select = dialog_yesno('Widevine CDM', config.get_localized_string(70808))
|
||||||
|
if select > 0:
|
||||||
|
if not 'arm' in platform['arch']:
|
||||||
|
last_version = downloadpage('https://dl.google.com/widevine-cdm/versions.txt').data.split()[-1]
|
||||||
|
download_widevine(last_version, platform, path)
|
||||||
|
else:
|
||||||
|
json = downloadpage('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json').data
|
||||||
|
devices = jsontools.load(json)
|
||||||
|
download_chromeos_image(devices, platform, path)
|
||||||
|
|
||||||
|
# if Widevine CDM is outdated
|
||||||
|
elif platform['os'] != 'android':
|
||||||
|
select = dialog_yesno(config.get_localized_string(70810),config.get_localized_string(70809))
|
||||||
|
if select > 0:
|
||||||
|
if not 'arm' in platform['arch']:
|
||||||
|
last_version = downloadpage('https://dl.google.com/widevine-cdm/versions.txt').data.split()[-1]
|
||||||
|
current_version = jsontools.load(open(os.path.join(path, 'manifest.json')).read())['version']
|
||||||
|
if LooseVersion(last_version) > LooseVersion(current_version):
|
||||||
|
download_widevine(last_version, platform, path)
|
||||||
|
else:
|
||||||
|
devices = jsontools.load(downloadpage('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json').data)
|
||||||
|
current_version = jsontools.load(open(os.path.join(path, 'config.json')).read())['version']
|
||||||
|
last_version = best_chromeos_image(devices)['version']
|
||||||
|
if LooseVersion(last_version) > LooseVersion(current_version):
|
||||||
|
download_chromeos_image(devices, platform, path)
|
||||||
|
|
||||||
|
|
||||||
|
def download_widevine(version, platform, path):
|
||||||
|
# for x86 architectures
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from xbmcaddon import Addon
|
||||||
|
from core import downloadtools
|
||||||
|
archiveName = 'https://dl.google.com/widevine-cdm/' + version + '-' + platform['os'] + '-' + platform['arch'] + '.zip'
|
||||||
|
fileName = config.get_temp_file('widevine.zip')
|
||||||
|
if not os.path.exists(archiveName):
|
||||||
|
if not os.path.exists(fileName):
|
||||||
|
downloadtools.downloadfile(archiveName, fileName, header='Download Widevine CDM')
|
||||||
|
zip_obj = ZipFile(fileName)
|
||||||
|
for filename in zip_obj.namelist():
|
||||||
|
zip_obj.extract(filename, path)
|
||||||
|
zip_obj.close()
|
||||||
|
os.remove(fileName)
|
||||||
|
|
||||||
|
|
||||||
|
def download_chromeos_image(devices, platform, path):
|
||||||
|
# for arm architectures
|
||||||
|
from core import downloadtools
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from core import jsontools
|
||||||
|
best = best_chromeos_image(devices)
|
||||||
|
archiveName = best['url']
|
||||||
|
version = best['version']
|
||||||
|
|
||||||
|
fileName = config.get_temp_file(archiveName.split('/')[-1])
|
||||||
|
if not os.path.exists(fileName):
|
||||||
|
downloadtools.downloadfile(archiveName, fileName, header='Download Widevine CDM')
|
||||||
|
from lib.arm_chromeos import ChromeOSImage
|
||||||
|
ChromeOSImage(fileName).extract_file(
|
||||||
|
filename='libwidevinecdm.so',
|
||||||
|
extract_path=os.path.join(path),
|
||||||
|
progress=dialog_progress(config.get_localized_string(70811),config.get_localized_string(70812)))
|
||||||
|
recovery_file = os.path.join(path, os.path.basename('https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.json'))
|
||||||
|
config_file = os.path.join(path, 'config.json')
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.mkdir(path)
|
||||||
|
with open(recovery_file, 'w') as reco_file:
|
||||||
|
reco_file.write(jsontools.dump(devices, indent=4))
|
||||||
|
reco_file.close()
|
||||||
|
with open(config_file, 'w') as conf_file:
|
||||||
|
conf_file.write(jsontools.dump(best))
|
||||||
|
conf_file.close()
|
||||||
|
os.remove(fileName)
|
||||||
|
|
||||||
|
def best_chromeos_image(devices):
|
||||||
|
best = None
|
||||||
|
for device in devices:
|
||||||
|
# Select ARM hardware only
|
||||||
|
for arm_hwid in ['BIG','BLAZE','BOB','DRUWL','DUMO','ELM','EXPRESSO','FIEVEL','HANA','JAQ','JERRY','KEVIN','KITTY','MICKEY','MIGHTY','MINNIE','PHASER','PHASER360','PI','PIT','RELM','SCARLET','SKATE','SNOW','SPEEDY','SPRING','TIGER']:
|
||||||
|
if arm_hwid in device['hwidmatch']:
|
||||||
|
hwid = arm_hwid
|
||||||
|
break # We found an ARM device, rejoice !
|
||||||
|
else:
|
||||||
|
continue # Not ARM, skip this device
|
||||||
|
|
||||||
|
device['hwid'] = hwid
|
||||||
|
|
||||||
|
# Select the first ARM device
|
||||||
|
if best is None:
|
||||||
|
best = device
|
||||||
|
continue # Go to the next device
|
||||||
|
|
||||||
|
# Skip identical hwid
|
||||||
|
if hwid == best['hwid']:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Select the newest version
|
||||||
|
from distutils.version import LooseVersion # pylint: disable=import-error,no-name-in-module,useless-suppression
|
||||||
|
if LooseVersion(device['version']) > LooseVersion(best['version']):
|
||||||
|
logger.info('%s (%s) is newer than %s (%s)' % (device['hwid'], device['version'], best['hwid'], best['version']))
|
||||||
|
best = device
|
||||||
|
|
||||||
|
# Select the smallest image (disk space requirement)
|
||||||
|
elif LooseVersion(device['version']) == LooseVersion(best['version']):
|
||||||
|
if int(device['filesize']) + int(device['zipfilesize']) < int(best['filesize']) + int(best['zipfilesize']):
|
||||||
|
logger.info('%s (%d) is smaller than %s (%d)' % (device['hwid'], int(device['filesize']) + int(device['zipfilesize']), best['hwid'], int(best['filesize']) + int(best['zipfilesize'])))
|
||||||
|
best = device
|
||||||
|
return best
|
||||||
|
|
||||||
|
def get_platform():
|
||||||
|
import platform
|
||||||
|
build = xbmc.getInfoLabel("System.BuildVersion")
|
||||||
|
kodi_version = int(build.split()[0][:2])
|
||||||
|
ret = {
|
||||||
|
"auto_arch": sys.maxsize > 2 ** 32 and "64-bit" or "32-bit",
|
||||||
|
"arch": sys.maxsize > 2 ** 32 and "x64" or "ia32",
|
||||||
|
"os": "",
|
||||||
|
"version": platform.release(),
|
||||||
|
"kodi": kodi_version,
|
||||||
|
"build": build
|
||||||
|
}
|
||||||
|
if xbmc.getCondVisibility("system.platform.android"):
|
||||||
|
ret["os"] = "android"
|
||||||
|
if "arm" in platform.machine() or "aarch" in platform.machine():
|
||||||
|
ret["arch"] = "arm"
|
||||||
|
if "64" in platform.machine() and ret["auto_arch"] == "64-bit":
|
||||||
|
ret["arch"] = "arm64"
|
||||||
|
elif xbmc.getCondVisibility("system.platform.linux"):
|
||||||
|
ret["os"] = "linux"
|
||||||
|
if "aarch" in platform.machine() or "arm64" in platform.machine():
|
||||||
|
if xbmc.getCondVisibility("system.platform.linux.raspberrypi"):
|
||||||
|
ret["arch"] = "armv7"
|
||||||
|
elif ret["auto_arch"] == "32-bit":
|
||||||
|
ret["arch"] = "armv7"
|
||||||
|
elif ret["auto_arch"] == "64-bit":
|
||||||
|
ret["arch"] = "arm64"
|
||||||
|
elif platform.architecture()[0].startswith("32"):
|
||||||
|
ret["arch"] = "arm"
|
||||||
|
else:
|
||||||
|
ret["arch"] = "arm64"
|
||||||
|
elif "armv7" in platform.machine():
|
||||||
|
ret["arch"] = "armv7"
|
||||||
|
elif "arm" in platform.machine():
|
||||||
|
ret["arch"] = "arm"
|
||||||
|
elif xbmc.getCondVisibility("system.platform.xbox"):
|
||||||
|
ret["os"] = "win"
|
||||||
|
ret["arch"] = "x64"
|
||||||
|
elif xbmc.getCondVisibility("system.platform.windows"):
|
||||||
|
ret["os"] = "win"
|
||||||
|
if platform.machine().endswith('64'):
|
||||||
|
ret["arch"] = "x64"
|
||||||
|
elif xbmc.getCondVisibility("system.platform.osx"):
|
||||||
|
ret["os"] = "mac"
|
||||||
|
ret["arch"] = "x64"
|
||||||
|
elif xbmc.getCondVisibility("system.platform.ios"):
|
||||||
|
ret["os"] = "ios"
|
||||||
|
ret["arch"] = "arm"
|
||||||
|
|
||||||
|
return ret
|
||||||
@@ -6031,6 +6031,42 @@ msgctxt "#70807"
|
|||||||
msgid "Elementum does not support network folder downloads, do you want to change the download location?"
|
msgid "Elementum does not support network folder downloads, do you want to change the download location?"
|
||||||
msgstr "Elementum non supporta i download su cartella di rete, vuoi cambiare il percorso di download?"
|
msgstr "Elementum non supporta i download su cartella di rete, vuoi cambiare il percorso di download?"
|
||||||
|
|
||||||
|
msgctxt "#70808"
|
||||||
|
msgid "In order to view this content you need to install [B]Widevine CDM[/B]. Do you want to install it?"
|
||||||
|
msgstr "Per poter visionare questo contenuto devi installare [B]Widevine CDM[/B]. Vuoi installarlo?"
|
||||||
|
|
||||||
|
msgctxt "#70809"
|
||||||
|
msgid "An update of [B]Widevine CDM[/B] is available. Do you want to install it?"
|
||||||
|
msgstr "È disponibile un aggiornamento di [B]Widevine CDM[/B]. Vuoi installarlo?"
|
||||||
|
|
||||||
|
msgctxt "#70810"
|
||||||
|
msgid "Update available"
|
||||||
|
msgstr "Aggiornamento disponibile"
|
||||||
|
|
||||||
|
msgctxt "#70811"
|
||||||
|
msgid "Extracting Widevine CDM"
|
||||||
|
msgstr "Estrazione di Widevine CDM"
|
||||||
|
|
||||||
|
msgctxt "#70812"
|
||||||
|
msgid "Preparing downloaded image..."
|
||||||
|
msgstr "Preparazione dell'immagine scaricata..."
|
||||||
|
|
||||||
|
msgctxt "#70813"
|
||||||
|
msgid "Identifying wanted partition..."
|
||||||
|
msgstr "Identificazione della partizione desiderata..."
|
||||||
|
|
||||||
|
msgctxt "#70814"
|
||||||
|
msgid "Scanning the filesystem for the Widevine CDM..."
|
||||||
|
msgstr "Scansione del filesystem per Widevine CDM..."
|
||||||
|
|
||||||
|
msgctxt "#70815"
|
||||||
|
msgid "Widevine CDM found, analyzing..."
|
||||||
|
msgstr "Widevine CDM trovato, analisi..."
|
||||||
|
|
||||||
|
msgctxt "#70816"
|
||||||
|
msgid "Extracting Widevine CDM from image..."
|
||||||
|
msgstr "Estrazione di Widevine CDM dall'immagine..."
|
||||||
|
|
||||||
# DNS start [ settings and declaration ]
|
# DNS start [ settings and declaration ]
|
||||||
msgctxt "#707401"
|
msgctxt "#707401"
|
||||||
msgid "Enable DNS check alert"
|
msgid "Enable DNS check alert"
|
||||||
|
|||||||
@@ -6031,6 +6031,42 @@ msgctxt "#70807"
|
|||||||
msgid "Elementum does not support network folder downloads, do you want to change the download location?"
|
msgid "Elementum does not support network folder downloads, do you want to change the download location?"
|
||||||
msgstr "Elementum non supporta i download su cartella di rete, vuoi cambiare il percorso di download?"
|
msgstr "Elementum non supporta i download su cartella di rete, vuoi cambiare il percorso di download?"
|
||||||
|
|
||||||
|
msgctxt "#70808"
|
||||||
|
msgid "In order to view this content you need to install [B]Widevine CDM[/B]. Do you want to install it?"
|
||||||
|
msgstr "Per poter visionare questo contenuto devi installare [B]Widevine CDM[/B]. Vuoi installarlo?"
|
||||||
|
|
||||||
|
msgctxt "#70809"
|
||||||
|
msgid "An update of [B]Widevine CDM[/B] is available. Do you want to install it?"
|
||||||
|
msgstr "È disponibile un aggiornamento di [B]Widevine CDM[/B]. Vuoi installarlo?"
|
||||||
|
|
||||||
|
msgctxt "#70810"
|
||||||
|
msgid "Update available"
|
||||||
|
msgstr "Aggiornamento disponibile"
|
||||||
|
|
||||||
|
msgctxt "#70811"
|
||||||
|
msgid "Extracting Widevine CDM"
|
||||||
|
msgstr "Estrazione di Widevine CDM"
|
||||||
|
|
||||||
|
msgctxt "#70812"
|
||||||
|
msgid "Preparing downloaded image..."
|
||||||
|
msgstr "Preparazione dell'immagine scaricata..."
|
||||||
|
|
||||||
|
msgctxt "#70813"
|
||||||
|
msgid "Identifying wanted partition..."
|
||||||
|
msgstr "Identificazione della partizione desiderata..."
|
||||||
|
|
||||||
|
msgctxt "#70814"
|
||||||
|
msgid "Scanning the filesystem for the Widevine CDM..."
|
||||||
|
msgstr "Scansione del filesystem per Widevine CDM..."
|
||||||
|
|
||||||
|
msgctxt "#70815"
|
||||||
|
msgid "Widevine CDM found, analyzing..."
|
||||||
|
msgstr "Widevine CDM trovato, analisi..."
|
||||||
|
|
||||||
|
msgctxt "#70816"
|
||||||
|
msgid "Extracting Widevine CDM from image..."
|
||||||
|
msgstr "Estrazione di Widevine CDM dall'immagine..."
|
||||||
|
|
||||||
# DNS start [ settings and declaration ]
|
# DNS start [ settings and declaration ]
|
||||||
msgctxt "#707401"
|
msgctxt "#707401"
|
||||||
msgid "Enable DNS check alert"
|
msgid "Enable DNS check alert"
|
||||||
|
|||||||
Reference in New Issue
Block a user