# encoding: utf-8 # # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import unicode_literals, absolute_import, division import sys import json import io import os.path from datetime import datetime, timedelta from .timeconv import isodate2date import xbmc import xbmcgui import xbmcplugin import xbmcaddon if sys.version_info[0] >= 3: import urllib.request as urllib2 from urllib.parse import urlencode, parse_qsl, quote_plus unicode = str else: import urllib2 from urllib import urlencode, quote_plus from urlparse import parse_qsl from .log import LOG from .movistar import * from .addon import * from .gui import * from .useragent import useragent kodi_version= int(xbmc.getInfoLabel('System.BuildVersion')[:2]) # Get the plugin url in plugin:// notation. _url = sys.argv[0] # Get the plugin handle as an integer number. _handle = int(sys.argv[1]) def get_url(**kwargs): for key, value in kwargs.items(): if isinstance(value, unicode): kwargs[key] = value.encode('utf-8') return '{0}?{1}'.format(_url, urlencode(kwargs)) def play(params): LOG('play - params: {}'.format(params)) if not 'url' in params: show_notification(addon.getLocalizedString(30204)) return url = params['url'] channel_id = params['id'] stype = params['stype'] token = m.account['ssp_token'] import inputstreamhelper is_helper = inputstreamhelper.Helper('mpd', drm='com.widevine.alpha') if not is_helper.check_inputstream(): show_notification(addon.getLocalizedString(30202)) return """ if addon.getSettingBool('reregister'): m.unregister_device() m.register_device() """ session_opened = False if addon.getSettingBool('open_session') or stype == 'vod': d = m.open_session(params['session_request']) session_opened = True LOG('Open session: d: {}'.format(d)) if d['resultCode'] != 0: show_notification(d['resultText']) return if 'resultData' in d and 'cToken' in d['resultData']: token = d['resultData']['cToken'] if stype == 'vod': d = m.delete_session() session_opened = False LOG('Delete session: d: {}'.format(d)) LOG("token: {}".format(token)) if stype in ['u7d', 'rec']: d = m.get_u7d_url(url) if 'resultText' in d: show_notification(d['resultText']) return else: url = d['url'] #if True: # url = url.replace('DASH_WPC_WIDEVINE', 'DASH_TV_WIDEVINE') # U7D from start and end times #if stype == 'tv' and all(param in params for param in ['cas_id', 'start_time', 'end_time']): # start = datetime.utcfromtimestamp(int(params['start_time'])) # end = datetime.utcfromtimestamp(int(params['end_time'])) # catchup_url = 'https://stover-wp0.cdn.telefonica.com/{cas_id}/vxfmt=dp/Manifest.mpd?device_profile=DASH_TV_WIDEVINE&start_time={start_time}&end_time={end_time}' # url = catchup_url.format(cas_id=params['cas_id'], start_time=start.strftime('%Y-%m-%dT%H:%M:%SZ'), end_time=end.strftime('%Y-%m-%dT%H:%M:%SZ')) # LOG('url from capchup: {}'.format(url)) # Read the proxy address proxy = addon.getSetting('proxy_address') LOG('proxy address: {}'.format(proxy)) if addon.getSettingBool('manifest_modification') and proxy: url = '{}/?manifest={}'.format(proxy, url) LOG("url: {}".format(url)) headers = 'Content-Type=application/octet-stream' headers += '&User-Agent=' + useragent headers += '&Accept=*/*&Accept-Language=es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3' headers += '&Referer=https://ver.movistarplus.es/' headers += '&Origin=https://ver.movistarplus.es' #headers += '&Host=wv-ottlic-f3.imagenio.telefonica.net' manifest_headers = 'User-Agent=' + useragent if True: #stype in ['tv', 'u7d', 'rec']: cdn_token = m.cache.load('cdn.conf', 60) if not cdn_token: cdn_token = m.get_cdntoken() if not cdn_token: time.sleep(2) cdn_token = m.get_cdntoken() if cdn_token: m.cache.save_file('cdn.conf', cdn_token) else: show_notification('Ha pasado algo') return #LOG('cdn_token: {}'.format(cdn_token)) manifest_headers += '&x-tcdn-token=' + cdn_token license_url = 'https://wv-ottlic-f3.imagenio.telefonica.net/TFAESP/wvls/contentlicenseservice/v1/licenses' certificate = ( 'CsECCAMSEBcFuRfMEgSGiwYzOi93KowYgrSCkgUijgIwggEKAoIBAQCZ7Vs7Mn2rXiTvw7YqlbWY' 'UgrVvMs3UD4GRbgU2Ha430BRBEGtjOOtsRu4jE5yWl5KngeVKR1YWEAjp+GvDjipEnk5MAhhC28V' 'jIeMfiG/+/7qd+EBnh5XgeikX0YmPRTmDoBYqGB63OBPrIRXsTeo1nzN6zNwXZg6IftO7L1KEMpH' 'SQykfqpdQ4IY3brxyt4zkvE9b/tkQv0x4b9AsMYE0cS6TJUgpL+X7r1gkpr87vVbuvVk4tDnbNfF' 'XHOggrmWEguDWe3OJHBwgmgNb2fG2CxKxfMTRJCnTuw3r0svAQxZ6ChD4lgvC2ufXbD8Xm7fZPvT' 'CLRxG88SUAGcn1oJAgMBAAE6FGxpY2Vuc2Uud2lkZXZpbmUuY29tEoADrjRzFLWoNSl/JxOI+3u4' 'y1J30kmCPN3R2jC5MzlRHrPMveoEuUS5J8EhNG79verJ1BORfm7BdqEEOEYKUDvBlSubpOTOD8S/' 'wgqYCKqvS/zRnB3PzfV0zKwo0bQQQWz53ogEMBy9szTK/NDUCXhCOmQuVGE98K/PlspKkknYVeQr' 'OnA+8XZ/apvTbWv4K+drvwy6T95Z0qvMdv62Qke4XEMfvKUiZrYZ/DaXlUP8qcu9u/r6DhpV51Wj' 'x7zmVflkb1gquc9wqgi5efhn9joLK3/bNixbxOzVVdhbyqnFk8ODyFfUnaq3fkC3hR3f0kmYgI41' 'sljnXXjqwMoW9wRzBMINk+3k6P8cbxfmJD4/Paj8FwmHDsRfuoI6Jj8M76H3CTsZCZKDJjM3BQQ6' 'Kb2m+bQ0LMjfVDyxoRgvfF//M/EEkPrKWyU2C3YBXpxaBquO4C8A0ujVmGEEqsxN1HX9lu6c5OMm' '8huDxwWFd7OHMs3avGpr7RP7DUnTikXrh6X0') play_item = xbmcgui.ListItem(path= url) license_type = 'com.widevine.alpha' license_key = '' if format(addon.getSetting('drm_type')) == 'Playready': license_type = 'com.microsoft.playready' if addon.getSettingBool('use_proxy_for_license') and proxy: request_id = str(int(time.time()*1000)) license_key = '{}/license?token={}&stype={}&session_request={}&request_id={}'.format(proxy, quote_plus(token), stype, quote_plus(params['session_request']), request_id) LOG('license_key: {}'.format(license_key)) else: license_key = license_url headers += '&nv-authorizations={}'.format(token) if kodi_version > 20: play_item.setProperty('inputstream.adaptive.drm_legacy', '{}|{}|{}'.format(license_type, license_key, headers)) else: play_item.setProperty('inputstream.adaptive.license_type', license_type) play_item.setProperty('inputstream.adaptive.license_key', '{}|{}|R{{SSM}}|'.format(license_key, headers)) play_item.setProperty('inputstream.adaptive.manifest_type', 'mpd') #play_item.setProperty('inputstream.adaptive.manifest_type', 'hls') play_item.setProperty('inputstream.adaptive.stream_headers', manifest_headers) play_item.setProperty('inputstream.adaptive.manifest_headers', manifest_headers) play_item.setProperty('inputstream.adaptive.server_certificate', certificate) #play_item.setProperty('inputstream.adaptive.license_flags', 'persistent_storage') #play_item.setProperty('inputstream.adaptive.license_flags', 'force_secure_decoder') if stype == 'u7d': play_item.setProperty('inputstream.adaptive.play_timeshift_buffer', 'true') if kodi_version < 19: play_item.setProperty('inputstreamaddon', 'inputstream.adaptive') else: play_item.setProperty('inputstream', 'inputstream.adaptive') play_item.setMimeType('application/dash+xml') play_item.setContentLookup(False) # Add info if addon.getSettingBool('add_extra_info') and stype in ['vod', 'u7d', 'rec']: t = {'id': params['id']} if 'show_id' in params: t['show_id'] = params['show_id'] m.add_video_extra_info(t) play_item.setInfo('video', t['info']) play_item.setArt(t['art']) # Subtitles if stype == 'vod' and addon.getSettingBool('use_ttml2ssa'): # Convert subtitles from ttml2ssa import Ttml2SsaAddon ttml = Ttml2SsaAddon() #ttml.use_language_filter = False subtype = ttml.subtitle_type() subfolder = os.path.join(profile_dir, 'subtitles') if not os.path.exists(subfolder): os.makedirs(subfolder) sublist = m.get_subtitles(params['url']) LOG('sublist: {}'.format(sublist)) subpaths = [] for sub in sublist: filename = os.path.join(subfolder, sub['lang']) LOG('Converting {}'.format(sub['filename'])) subheaders = m.net.headers.copy() subheaders['x-tcdn-token'] = cdn_token response = m.net.session.get(sub['url'], allow_redirects=True, headers=subheaders) content = response.content with io.open(filename + '.ttml', 'w', encoding='utf-8', newline='') as handle: handle.write(content.decode('utf-8')) ttml.parse_ttml_from_string(content) if subtype != 'srt': filename_ssa = filename + '.ssa' ttml.write2file(filename_ssa) subpaths.append(filename_ssa) if subtype != 'ssa': filename_srt = filename if (subtype == 'both'): filename_srt += '.SRT' filename_srt += '.srt' ttml.write2file(filename_srt) subpaths.append(filename_srt) play_item.setSubtitles(subpaths) #if True: # m.unregister_device() # m.register_device() xbmcplugin.setResolvedUrl(_handle, True, listitem=play_item) LOG('**** session_opened: {}'.format(session_opened)) watermarks = [] if stype == 'tv' and 'uid' in params: watermarks = m.get_watermarks(params['uid']) LOG('watermarks: {}'.format(watermarks)) if session_opened or watermarks: window = xbmcgui.Window(12005) label = xbmcgui.ControlLabel(0, 0, 400, 20, m.account['id'], textColor='0xFFFFFFFF', alignment=6) from .player import MyPlayer player = MyPlayer() monitor = xbmc.Monitor() while not monitor.abortRequested() and player.running: monitor.waitForAbort(10) #LOG('**** waiting') if player.isPlaying() and watermarks: now = isodate2date(datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')) for wm in list(watermarks): start = isodate2date(wm['start']) stop = isodate2date(wm['stop']) if now >= start: watermarks.remove(wm) if now < stop: duration = (stop - start).total_seconds() #show_notification(m.account['id'], xbmcgui.NOTIFICATION_INFO) w = window.getWidth() h = window.getHeight() #LOG('window h: {} w: {}'.format(h, w)) pos_x = w-label.getWidth()-60 pos_y = h-200 label.setPosition(pos_x, pos_y) window.addControl(label) time.sleep(duration) window.removeControl(label) if session_opened: d = m.delete_session() LOG('Delete session: d: {}'.format(d)) LOG('Playback finished') def add_videos(category, ctype, videos, ref=None, url_next=None, url_prev=None, from_wishlist=False): #LOG("category: {} ctype: {}".format(category, ctype)) xbmcplugin.setPluginCategory(_handle, category) xbmcplugin.setContent(_handle, ctype) if ctype == 'movies' or ctype == 'seasons': xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_UNSORTED) xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL) xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_TITLE) xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_VIDEO_YEAR) xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LASTPLAYED) if ctype == 'episodes': xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_EPISODE) """ if url_prev: list_item = xbmcgui.ListItem(label = addon.getLocalizedString(30110)) # Previous page xbmcplugin.addDirectoryItem(_handle, get_url(action=ref, url=url_prev, name=category), list_item, True) """ for t in videos: #LOG("t: {}".format(t)) if 'subscribed' in t: if addon.getSettingBool('only_subscribed') and t['subscribed'] == False: continue t['info']['title'] = m.colorize_title(t) if 'availability' in t: ends = int(t['availability'].get('end', '0')) if ends > 0: now = int(time.time()*1000) n_hours = int((ends - now) / (1000 * 60 * 60)) n_days = int(n_hours / 24) if (n_days <= addon.getSettingInt('expdays')): if n_days < 1: t['info']['title'] += ' [COLOR red](' + addon.getLocalizedString(30401).format(n_hours) + ')[/COLOR]' else: t['info']['title'] += ' [COLOR red](' + addon.getLocalizedString(30400).format(n_days) + ')[/COLOR]' title_name = t['info']['title'] if not 'type' in t: continue wishlist_action = None if t['type'] in ['movie', 'series', 'season']: id = t['id'] stype = 'vod' possible_to_add = False if from_wishlist: # Remove from wishlist if 'favorite_data' in t: if 'favorites2' in t['favorite_data']: id = t['favorite_data']['favorites2']['id'] stype = t['favorite_data']['favorites2']['family'] possible_to_add = True elif t['type'] == 'season' and 'favorites2.season' in t['favorite_data']: id = t['favorite_data']['favorites2.season']['id'] stype = t['favorite_data']['favorites2.season']['family'] possible_to_add = True else: # Add to wishlist if t['type'] in ['series', 'season']: possible_to_add = t.get('seguible', False) if t['type'] == 'movie': if t.get('stream_type') == 'vod': possible_to_add = t['url'] != '' if 'show_id' in t: possible_to_add = t['url'] != '' stype = 'tv' id = t['show_id'] if possible_to_add: if not from_wishlist: op = 'add' message = 30175 else: op = 'delete' message = 30176 wishlist_action = (addon.getLocalizedString(message), "RunPlugin(" + get_url(action='to_wishlist', id=id, op=op, stype=stype) + ")") if t['type'] == 'movie': list_item = xbmcgui.ListItem(label = title_name) #if t['url'] == '': # t['info']['title'] = '[COLOR gray]' + t['info']['title'] +'[/COLOR]' list_item.setProperty('IsPlayable', 'true') list_item.setInfo('video', t['info']) list_item.setArt(t['art']) actions = [] if t.get('stream_type') == 'u7d': #LOG(t) if 'show_id' in t and not t.get('aired', False): record_program_action = (addon.getLocalizedString(30171), "RunPlugin(" + get_url(action='add_recording', id=t['show_id']) + ")") actions.append(record_program_action) if 'serie_id' in t: record_season_action = (addon.getLocalizedString(30169), "RunPlugin(" + get_url(action='add_recording_season', id=t['serie_id']) + ")") actions.append(record_season_action) if 'rec' in t: action = get_url(action='delete_recording', id=t['rec']['id'], name=t['rec']['name']) actions.append((addon.getLocalizedString(30173), "RunPlugin(" + action + ")")) if wishlist_action: actions.append(wishlist_action) if len(actions) > 0: #LOG(actions) list_item.addContextMenuItems(actions) url = get_url(action='play', id=t['id'], url=t['url'], session_request=t['session_request'], stype=t['stream_type']) if 'show_id' in t: url += '&show_id={}'.format(t['show_id']) if 'uid' in t: url += '&uid={}'.format(t['uid']) xbmcplugin.addDirectoryItem(_handle, url, list_item, False) elif t['type'] == 'series': list_item = xbmcgui.ListItem(label = title_name) list_item.setInfo('video', t['info']) list_item.setArt(t['art']) if wishlist_action: list_item.addContextMenuItems([wishlist_action]) xbmcplugin.addDirectoryItem(_handle, get_url(action='series', id=t['id'], name=title_name), list_item, True) elif t['type'] == 'season': list_item = xbmcgui.ListItem(label = title_name) list_item.setInfo('video', t['info']) list_item.setArt(t['art']) if wishlist_action: list_item.addContextMenuItems([wishlist_action]) xbmcplugin.addDirectoryItem(_handle, get_url(action='season', id=t['id'], name=title_name), list_item, True) elif t['type'] == 'category': list_item = xbmcgui.ListItem(label = title_name) #list_item.setInfo('video', t['info']) #list_item.setArt(t['art']) xbmcplugin.addDirectoryItem(_handle, get_url(action='category', id=t['id'], name=title_name), list_item, True) if url_next: list_item = xbmcgui.ListItem(label = addon.getLocalizedString(30109)) # Next page xbmcplugin.addDirectoryItem(_handle, get_url(action=ref, url=url_next, from_wishlist=from_wishlist, name=category), list_item, True) xbmcplugin.endOfDirectory(_handle) def list_devices(params): LOG('list_devices: params: {}'.format(params)) devices = m.get_devices() if 'id' in params: if params['name'] == 'select': LOG('Selecting device {}'.format(params['id'])) m.change_device(params['id']) elif params['name'] == 'close': LOG('Closing session {}'.format(params['id'])) m.delete_session(params['id']) elif params['name'] == 'delete': LOG('Removing device {}'.format(params['id'])) m.delete_device(params['id']) if params['id'] == m.account['device_id']: LOG('Registering device') m.register_device() xbmc.executebuiltin("Container.Refresh") return open_folder(addon.getLocalizedString(30108)) # Devices for d in devices: name = d['name'] +' - '+ d['type'] + ' (' + d['reg_date'] + ')' if d['playing']: name += ' [' + d['playing'] + ']' name += ' ['+ d['id'][:5] +']' if d['id'] == m.account['device_id']: name = '[B][COLOR blue]' + name + '[/COLOR][/B]' select_action = get_url(action='devices', id=d['id'], name='select') close_action = get_url(action='devices', id=d['id'], name='close') remove_action = get_url(action='devices', id=d['id'], name='delete') cm = [(addon.getLocalizedString(30150), "RunPlugin(" + close_action + ")"), (addon.getLocalizedString(30151), "RunPlugin(" + remove_action + ")")] if d['type_code'] == 'WP': cm.insert(0, (addon.getLocalizedString(30152), "RunPlugin(" + select_action + ")")) default_action = select_action else: default_action = close_action add_menu_option(name, default_action, cm) close_folder(cacheToDisc=False) def list_profiles(params): LOG('list_profiles: params: {}'.format(params)) profiles = m.get_profiles() if 'id' in params: if params['name'] == 'select': LOG('Selecting profile {}'.format(params['id'])) m.change_profile(params['id']) xbmc.executebuiltin("Container.Refresh") return open_folder(addon.getLocalizedString(30180)) # Profiles for p in profiles: name = p['name'] if p['id'] == m.account['profile_id']: name = '[B][COLOR blue]' + name + '[/COLOR][/B]' img_url = m.get_profile_image_url(p['image_id']) art = {'icon': img_url} if img_url else None select_action = get_url(action='profiles', id=p['id'], name='select') add_menu_option(name, select_action, art=art) close_folder(cacheToDisc=False) def list_epg(params): LOG('list_epg: {}'.format(params)) from .timeconv import my_strftime if 'id' in params: if not 'date' in params: today = datetime.today() for i in range(6, 0, -1): past_date = today - timedelta(days=i) date = past_date.strftime('%Y-%m-%dT00:00:00') display_str = my_strftime(past_date, '%a %d') add_menu_option(display_str, get_url(action='epg', id=params['id'], name=params['name'], date=date)) add_videos(params['name'], 'movies', m.epg_to_movies(params['id'], params.get('date'), duration=1)) else: channels = m.get_channels() open_folder(addon.getLocalizedString(30107)) # EPG for t in channels: name = t['info']['title'] add_menu_option(name, get_url(action='epg', id=t['id'], name=name.encode('utf-8')), art=t['art']) close_folder() def listing(name, url): data = m.download_list(url, use_hz=False) l = [] url_next = None url_prev = None if 'Contenidos' in data: l = m.get_list(data['Contenidos']) url_next = data['next']['href'] if isinstance(data['next'], dict) and 'href' in data['next'] else None url_prev = data['prev']['href'] if isinstance(data['next'], dict) and 'prev' in data['next'] else None add_videos(name, 'movies', l, url_next=url_next, url_prev=url_prev, ref='listing') def listing_hz(name, url, from_wishlist=False): data = m.download_list(url, use_hz=True) l = [] url_next = None url_prev = None if 'Contenidos' in data: l = m.get_list(data['Contenidos']) url_next = data['next']['href'] if isinstance(data['next'], dict) and 'href' in data['next'] else None url_prev = data['prev']['href'] if isinstance(data['next'], dict) and 'prev' in data['next'] else None add_videos(name, 'movies', l, url_next=url_next, url_prev=url_prev, ref='listing_hz', from_wishlist=from_wishlist) def list_vod0(): open_folder(addon.getLocalizedString(30111)) # VOD name = addon.getLocalizedString(30105).encode('utf-8') add_menu_option(name, get_url(action='listing', name=name, url=m.get_vod_list_url(cat='movies'))) # Movies name = addon.getLocalizedString(30106).encode('utf-8') add_menu_option(name, get_url(action='listing', name=name, url=m.get_vod_list_url(cat='tvshows'))) # TV Shows name = addon.getLocalizedString(30120).encode('utf-8') add_menu_option(name, get_url(action='listing', name=name, url=m.get_vod_list_url(cat='documentaries'))) # Documentaries name = addon.getLocalizedString(30121).encode('utf-8') add_menu_option(name, get_url(action='listing', name=name, url=m.get_vod_list_url(cat='kids'))) # Kids sections = m.get_vod_sections() close_folder() def list_vod(): open_folder(addon.getLocalizedString(30111)) # VOD sections = m.get_vod_sections() for key, s in sections.items(): if not s['visible']: continue name = s['name'].encode('utf-8') add_menu_option(name, get_url(action='list_section', name=name, key=key)) close_folder() def list_section(key): open_folder(addon.getLocalizedString(30111)) # VOD sections = m.get_vod_sections() items = sections[key]['data'] for item in items: name = item['name'].encode('utf-8') add_menu_option(name, get_url(action='listing', name=name, url=item['url'])) close_folder() def search(params): search_term = params.get('search_term', None) if search_term: if sys.version_info[0] < 3: search_term = search_term.decode('utf-8') if params.get('name', None) == 'delete': m.delete_search(search_term) xbmc.executebuiltin("Container.Refresh") else: url = m.get_search_url(search_term) listing_hz(addon.getLocalizedString(30117), url) return if params.get('name', None) == 'new': search_term = input_window(addon.getLocalizedString(30116)) # Search term if search_term: if sys.version_info[0] < 3: search_term = search_term.decode('utf-8') m.add_search(search_term) xbmc.executebuiltin("Container.Refresh") return open_folder(addon.getLocalizedString(30113)) # Search add_menu_option(addon.getLocalizedString(30113), get_url(action='search', name='new')) # New search for i in reversed(m.search_list): remove_action = get_url(action='search', search_term=i, name='delete') cm = [(addon.getLocalizedString(30114), "RunPlugin(" + remove_action + ")")] add_menu_option(i.encode('utf-8'), get_url(action='search', search_term=i), cm) close_folder(cacheToDisc=False) def order_recording(program_id): data = m.order_recording(program_id) if data and 'resultText' in data: show_notification(data['resultText']) else: show_notification(addon.getLocalizedString(30172), xbmcgui.NOTIFICATION_INFO) def order_recording_season(season_id): data = m.order_recording_season(season_id) if data and 'resultText' in data: show_notification(data['resultText']) else: show_notification(addon.getLocalizedString(30172), xbmcgui.NOTIFICATION_INFO) def delete_recording(id, name): if sys.version_info[0] < 3: name = name.decode('utf-8') res = xbmcgui.Dialog().yesno(addon.getLocalizedString(30173), addon.getLocalizedString(30174).format(name)) if res == True: m.delete_recording(id) xbmc.executebuiltin("Container.Refresh") def clear_session(): m.delete_session_files() def logout(): clear_session() m.cache.remove_file('auth.key') def login(): def ask_credentials(username='', password=''): username = input_window(addon.getLocalizedString(30163), username) # Username if username: password = input_window(addon.getLocalizedString(30164), password, hidden=True) # Password if password: return username, password return None, None store_credentials = addon.getSettingBool('store_credentials') if store_credentials: username, password = m.load_credentials() else: username, password = ('', '') username, password = ask_credentials(username, password) if username: if store_credentials: m.save_credentials(username, password) success, _ = m.login(username, password) if success: clear_session() else: show_notification(addon.getLocalizedString(30166)) # Failed def network_login(): account_number = addon.getSetting('account_number') if not account_number and not m.cache.load_file('account.json') and not m.cache.load_file('tokens.json'): account_number = input_window(addon.getLocalizedString(30502)) # Account number if not account_number: return addon.setSetting('account_number', account_number) # Keeps device_id.conf: clearing the session would register a new device. if m.try_network_login(account_number, force=True): show_notification(addon.getLocalizedString(30503), xbmcgui.NOTIFICATION_INFO) # Logged in xbmc.executebuiltin('Container.Refresh') else: reason = (m.network_login_result or (False, ''))[1] show_notification(addon.getLocalizedString(30504).format(reason)) # Failed def login_with_key(): filename = xbmcgui.Dialog().browseSingle(1, addon.getLocalizedString(30182), '', '.key') if filename: m.install_key_file(filename) clear_session() def export_key(): directory = xbmcgui.Dialog().browseSingle(0, addon.getLocalizedString(30185), '') if directory: m.export_key_file(directory + 'movistarplus.key') def import_credentials(): filename = xbmcgui.Dialog().browseSingle(1, addon.getLocalizedString(30193), '', '.json') if filename: m.import_credentials(filename) def export_credentials(): directory = xbmcgui.Dialog().browseSingle(0, addon.getLocalizedString(30194), '') if directory: m.export_credentials(os.path.join(directory, 'credenciales.json')) def select_account(id, name): m.switch_account(id) open_folder(name) add_menu_option(addon.getLocalizedString(30501), get_url(action='network_login')) # Login from home network add_menu_option(addon.getLocalizedString(30183), get_url(action='login')) # Login with username if addon.getSettingBool('enable_key_login'): add_menu_option(addon.getLocalizedString(30181), get_url(action='login_with_key')) # Login with key if os.path.exists(os.path.join(m.cache.config_directory, 'auth.key')): add_menu_option(addon.getLocalizedString(30184), get_url(action='export_key')) # Export key add_menu_option(addon.getLocalizedString(30150), get_url(action='logout')) # Close session add_menu_option(addon.getLocalizedString(30196), get_url(action='import_credentials')) if os.path.exists(os.path.join(m.cache.config_directory, 'credentials.json')): add_menu_option(addon.getLocalizedString(30195), get_url(action='export_credentials')) close_folder(cacheToDisc=False) def list_accounts(params): LOG('list_accounts: {}'.format(params)) if params.get('name') == 'new_account': m.create_new_account() accounts = m.get_accounts() open_folder(addon.getLocalizedString(30160)) # Accounts for account in accounts: name = account['name'] login = account.get('login') if login: name += ' ({})'.format(login) if account['id'] == m.account_dir: display_name = '[B][COLOR blue]' + name + '[/COLOR][/B]' else: display_name = name add_menu_option(display_name, get_url(action='select_account', id=account['id'], name=name)) add_menu_option(addon.getLocalizedString(30161), get_url(action='accounts', name='new_account')) # Add new close_folder(cacheToDisc=False) if params.get('name') == 'new_account': xbmc.executebuiltin('Container.Update({},replace)'.format(xbmc.getInfoLabel('Container.FolderPath'))) def iptv(params): LOG('iptv: params: {}'.format(params)) if m.logged: #try: if True: from .iptvmanager import IPTVManager port = int(params['port']) if params['action'] == 'iptv-channels': IPTVManager(port).send_channels(m) elif params['action'] == 'iptv-epg': IPTVManager(port).send_epg(m) #except: # pass def create_iptv_settings(): from .iptv import save_iptv_settings show_notification(addon.getLocalizedString(30319), xbmcgui.NOTIFICATION_INFO) output_file = 'instance-settings-91.xml' if kodi_version > 19 else 'settings.xml' epg_url = None if False: #addon.getSettingBool('use_external_epg'): epg_url = addon.getSetting('epg_url') try: pvr_addon = xbmcaddon.Addon('pvr.iptvsimple') pvr_dir = translatePath(pvr_addon.getAddonInfo('profile')) LOG('pvr_dir: {}'.format(pvr_dir)) filename = os.path.join(pvr_dir, output_file) if os.path.exists(filename): res = xbmcgui.Dialog().yesno(addon.getLocalizedString(30322), addon.getLocalizedString(30323)) if res == False: return save_iptv_settings(filename, 'KodiMov+', 'kodimovplus', epg_url) export_epg_now() except: show_notification(addon.getLocalizedString(30324)) def export_channels_now(): if not m.logged: return channels_filename = os.path.join(profile_dir, 'channels.m3u8') if m.export_channels_to_m3u8(channels_filename, addon.getSettingBool('only_subscribed')): LOG('export_channels_now: channel list changed') def export_epg_now(): def report_progress(message): show_notification(addon.getLocalizedString(30314).format(message), xbmcgui.NOTIFICATION_INFO) if not m.logged: return only_subscribed = addon.getSettingBool('only_subscribed') channels_filename = os.path.join(profile_dir, 'channels.m3u8') epg_filename = os.path.join(profile_dir, 'epg.xml') show_notification(addon.getLocalizedString(30310), xbmcgui.NOTIFICATION_INFO) m.export_channels_to_m3u8(channels_filename, only_subscribed) if True: #not addon.getSettingBool('use_external_epg'): show_notification(addon.getLocalizedString(30311), xbmcgui.NOTIFICATION_INFO) m.export_epg_to_xml(epg_filename, addon.getSettingInt('export_days'), report_progress, only_subscribed) show_notification(addon.getLocalizedString(30313), xbmcgui.NOTIFICATION_INFO) def to_wishlist(params): stype = params['stype'] if params['op'] == 'add': retcode, message = m.add_to_wishlist(params['id'], stype) else: retcode, message = m.delete_from_wishlist(params['id'], stype) if retcode in [201, 204]: message = 30177 if params['op'] == 'add' else 30178 show_notification(addon.getLocalizedString(message), xbmcgui.NOTIFICATION_INFO) if params['op'] == 'delete': xbmc.executebuiltin("Container.Refresh") else: show_notification(str(retcode) +': '+ message) def router(paramstring): """ Router function that calls other functions depending on the provided paramstring :param paramstring: URL encoded plugin paramstring :type paramstring: str """ params = dict(parse_qsl(paramstring)) LOG('params: {}'.format(params)) if params: if params['action'] == 'play': play(params) elif params['action'] == 'tv': if addon.getSettingBool('channels_with_epg'): channels = m.get_channels_with_epg() else: channels = m.get_channels() add_videos(addon.getLocalizedString(30104), 'movies', channels) elif params['action'] == 'devices': list_devices(params) elif params['action'] == 'profiles': list_profiles(params) elif params['action'] == 'login_with_key': login_with_key() elif params['action'] == 'login': login() elif params['action'] == 'network_login': network_login() elif params['action'] == 'export_channels_now': export_channels_now() elif params['action'] == 'export_key': export_key() elif params['action'] == 'export_credentials': export_credentials() elif params['action'] == 'import_credentials': import_credentials() elif params['action'] == 'select_account': select_account(params['id'], params['name']) elif params['action'] == 'accounts': list_accounts(params) elif params['action'] == 'logout': logout() elif params['action'] == 'epg': list_epg(params) elif params['action'] == 'add_recording': order_recording(params['id']) elif params['action'] == 'delete_recording': delete_recording(params['id'], params['name']) elif params['action'] == 'add_recording_season': order_recording_season(params['id']) elif params['action'] == 'wishlist': # Wishlist listing_hz(addon.getLocalizedString(30102), m.get_wishlist_url(), from_wishlist=True) elif params['action'] == 'continue-watching': listing_hz(addon.getLocalizedString(30102), m.get_viewings_url()) elif params['action'] == 'recordings': # Recordings listing_hz(addon.getLocalizedString(30103), m.get_recordings_url()) elif params['action'] == 'listing': listing(params['name'], params['url']) elif params['action'] == 'listing_hz': listing_hz(params['name'], params['url'], params.get('from_wishlist')) elif params['action'] == 'series': add_videos(params['name'], 'seasons', m.get_seasons(params['id'])) elif params['action'] == 'season': add_videos(params['name'], 'episodes', m.get_episodes(params['id'])) elif params['action'] == 'vod': list_vod() elif params['action'] == 'list_section': list_section(params['key']) elif params['action'] == 'search': search(params) elif params['action'] == 'create_iptv_settings': create_iptv_settings() elif params['action'] == 'export_epg_now': export_epg_now() elif params['action'] == 'to_wishlist': to_wishlist(params) elif 'iptv' in params['action']: iptv(params) else: # Main open_folder(addon.getLocalizedString(30101)) # Menu if m.logged: add_menu_option(addon.getLocalizedString(30104), get_url(action='tv'), icon='tv.png') # TV add_menu_option(addon.getLocalizedString(30107), get_url(action='epg'), icon='epg.png') # EGP add_menu_option(addon.getLocalizedString(30102), get_url(action='wishlist'), icon='mylist.png') # My list add_menu_option(addon.getLocalizedString(30103), get_url(action='recordings'), icon='recording.png') # Recordings add_menu_option(addon.getLocalizedString(30122), get_url(action='continue-watching'), icon='continue.png') # Continue add_menu_option(addon.getLocalizedString(30111), get_url(action='vod'), icon='vod.png') # VOD add_menu_option(addon.getLocalizedString(30112), get_url(action='search'), icon='search.png') # Search add_menu_option(addon.getLocalizedString(30180), get_url(action='profiles'), icon='profiles.png') # Profiles add_menu_option(addon.getLocalizedString(30108), get_url(action='devices'), icon='devices.png') # Devices else: if m.expired_access_token: show_notification(addon.getLocalizedString(30208)) add_menu_option(addon.getLocalizedString(30501), get_url(action='network_login'), icon='account.png') # Login from home network add_menu_option(addon.getLocalizedString(30160), get_url(action='accounts'), icon='account.png') # Accounts add_menu_option(addon.getLocalizedString(30450), get_url(action='show_donation_dialog'), icon='qr.png') # Donation close_folder(cacheToDisc=False) def run(): # Call the router function and pass the plugin call parameters to it. # We use string slicing to trim the leading '?' from the plugin call paramstring params = sys.argv[2][1:] if 'show_donation_dialog' in params: from .customdialog import show_donation_dialog show_donation_dialog() return global m reuse_devices = addon.getSettingBool('reuse_devices') LOG('profile_dir: {}'.format(profile_dir)) LOG('reuse_devices: {}'.format(reuse_devices)) m = Movistar(profile_dir, reuse_devices=reuse_devices, network_login=addon.getSettingBool('network_login'), account_number=addon.getSetting('account_number')) m.add_extra_info = addon.getSettingBool('add_extra_info') m.hide_unplayable = addon.getSettingBool('hide_unplayable') m.add_extra_channels = addon.getSettingBool('extra_channels') if addon.getSettingBool('uhd'): m.quality = 'UHD' profile_id = addon.getSetting('profile_id').upper() LOG('profile_id: {}'.format(profile_id)) if profile_id not in ['', 'AUTO']: m.account['platform'] = profile_id # Clear cache LOG('Cleaning cache. {} files removed.'.format(m.cache.clear_cache())) if '/iptv/channels' in sys.argv[0]: params += '&action=iptv-channels' elif '/iptv/epg' in sys.argv[0]: params += '&action=iptv-epg' router(params)