def __init__(self): if "is_initiated" in self.__dict__: # This is not the first instance of PopupStyle, # no need to initiate anything return self.is_initiated = True gobject.GObject.__init__(self) self.globals = Globals() self.name = "DBX" self.settings = {} self.globals.connect("popup-style-changed", self.on_style_changed) self.on_style_changed()
def __init__(self, groupbutton): self.groupbutton_r = weakref.ref(groupbutton) self.menu_counter = 0 self.menu_items = ODict() self.globals = Globals() DockManagerItem.counter += 1 self.obj_path = "/net/launchpad/DockManager/Item" + \ str(DockManagerItem.counter) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, self.obj_path)
def __init__(self): super(_AmazonPlayer, self).__init__() self._g = Globals() self.sleeptm = 0.2 self.video_lastpos = 0 self.video_totaltime = 0 self.dbid = 0 self.seek = 0 self.url = '' self.extern = '' self.asin = '' self.cookie = None self.interval = 180 self.running = False
def _ParseStreams(suc, data, retmpd=False, bypassproxy=False): g = Globals() s = Settings() HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd and not bypassproxy: subUrls = [sub['url'] for sub in data['subtitles'] if 'url' in sub.keys()] if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str(hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue returl = urlset['url'] if bypassproxy else 'http://{}/mpd/{}'.format(s.proxyaddress, quote_plus(urlset['url'])) return (returl, subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)
def __init__(self, label, toggle_type="checkmark"): self.globals = Globals() CairoMenuItem.__init__(self, None) self.indicator = gtk.CheckMenuItem() self.indicator.set_draw_as_radio(toggle_type == "radio") self.area.label = gtk.Label() hbox = gtk.HBox() hbox.pack_start(self.indicator, False, padding=2) hbox.pack_start(self.area.label, False, padding=2) alignment = gtk.Alignment(0.5,0.5,0,0) alignment.add(hbox) alignment.show_all() self.area.add(alignment) color = self.globals.colors["color2"] self.set_label(label, color)
def __init__(self): super(_AmazonPlayer, self).__init__() self._g = Globals() self.sleeptm = 0.2 self.video_lastpos = 0 self.video_totaltime = 0 self.dbid = 0 self.asin = '' self.cookie = None self.interval = 180 self.running = False self.extern = False self.resume = 0 self.watched = 0 self.content = 0 self.resumedb = OSPJoin(g.DATA_PATH, 'resume.db')
def __init__(self, surface=None, expose_on_clear=False): gtk.EventBox.__init__(self) self.set_visible_window(False) self.area = gtk.Alignment(0, 0, 1, 1) self.add(self.area) self.area.show() self.globals = Globals() self.surface = surface self.expose_on_clear = expose_on_clear self.badge = None self.badge_text = None self.progress_bar = None self.progress = None self.bl_sid = self.globals.connect("badge-look-changed", self.__on_badge_look_changed) self.pbl_sid = self.globals.connect("progress-bar-look-changed", self.__on_progress_bar_look_changed)
def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.globals = Globals() self.set_spacing(0) self.set_border_width(0) self.toggle_button = CairoMenuItem(label) if label: if show_menu: color = self.globals.colors["color4"] else: color = self.globals.colors["color2"] self.toggle_button.set_label(label, color) self.pack_start(self.toggle_button) self.toggle_button.show() self.toggle_button.connect("clicked", self.toggle) self.menu = CairoVBox() self.menu.set_no_show_all(True) self.pack_start(self.menu) self.menu.set_border_width(10) self.show_menu = show_menu if show_menu: self.menu.show()
def PlayVideo(name, asin, adultstr, trailer, forcefb=0): g = Globals() s = Settings() def _check_output(*popenargs, **kwargs): p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) out, err = p.communicate() retcode = p.poll() if retcode != 0: c = kwargs.get("args") if c is None: c = popenargs[0] e = subprocess.CalledProcessError(retcode, c) e.output = str(out) + str(err) Log(e, Log.ERROR) return out.strip() def _playDummyVid(): dummy_video = OSPJoin(g.PLUGIN_PATH, 'resources', 'dummy.avi') xbmcplugin.setResolvedUrl(g.pluginhandle, True, xbmcgui.ListItem(path=dummy_video)) Log('Playing Dummy Video', Log.DEBUG) xbmc.Player().stop() return def _extrFr(data): fps_string = re.compile('frameRate="([^"]*)').findall(data)[0] fr = round(eval(fps_string + '.0'), 3) return str(fr).replace('.0', '') def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main and down_lang > 1: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage(xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ('' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if (p1 == p2): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath('special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % (sub['displayName'].strip(), sub['languageCode']) content = '' Log("Subtitle URL: %s" % (sub['url']), Log.DEBUG) with codecs.open(srtfile, 'w', encoding='utf-8') as srt: # Since dfxp provides no particular metadata and .srt are usually available on amazon's servers, # we try to download the .srt straight away to avoid conversion. Although we avoid it with RTL # languages, since we need to parse them anyway. if (sub['url'].endswith("dfxp")) and ('ar' != sub['languageCode']): subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL(subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang, Log.DEBUG) srt.write(content) continue content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) Log('Output %s' % srtfile, Log.DEBUG) # Apply a bunch of regex to the content instead of line-by-line to save computation time content = re.sub(r'<(|/)span[^>]*>', r'<\1i>', content) # Using (|<search>) instead of ()? to avoid py2.7 empty matching error content = re.sub(r'([0-9]{2}:[0-9]{2}:[0-9]{2})\.', r'\1,', content) # SRT-like timestamps content = re.sub(r'\s*<(?:tt:)?br\s*/>\s*', '\n', content) # Replace <br/> with actual new lines # Convert dfxp or ttml2 to srt num = 0 for tt in re.compile(r'<(?:tt:)?p begin="([^"]+)"[^>]*end="([^"]+)"[^>]*>\s*(.*?)\s*</(?:tt:)?p>', re.DOTALL).findall(content): text = tt[2] # Embed RTL and change the punctuation where needed if 'ar' == sub['languageCode']: from unicodedata import lookup text = re.sub('^', lookup('RIGHT-TO-LEFT EMBEDDING'), text, flags=re.MULTILINE) text = text.replace('?', '؟').replace(',', '،') for ec in escape_chars: text = text.replace(ec[0], ec[1]) num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt[0], tt[1], text)) Log('Conversion finished', Log.DEBUG) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str(hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217) def _getCmdLine(videoUrl, asin, method, fr): scr_path = g.addon.getSetting("scr_path") br_path = g.addon.getSetting("br_path").strip() scr_param = g.addon.getSetting("scr_param").strip() kiosk = g.addon.getSetting("kiosk") == 'true' appdata = g.addon.getSetting("ownappdata") == 'true' cust_br = g.addon.getSetting("cust_path") == 'true' nobr_str = getString(30198) frdetect = g.addon.getSetting("framerate") == 'true' if method == 1: if not xbmcvfs.exists(scr_path): return False, nobr_str if frdetect: suc, fr = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, useCookie=True)) if not fr else (True, fr) if not suc: return False, fr else: fr = '' return True, scr_path + ' ' + scr_param.replace('{f}', fr).replace('{u}', videoUrl) br_platform = (g.platform & -g.platform).bit_length() os_paths = [None, ('C:\\Program Files\\', 'C:\\Program Files (x86)\\'), ('/usr/bin/', '/usr/local/bin/'), 'open -a '][br_platform] # path(0,win,lin,osx), kiosk, profile, args br_config = [[(None, ['Internet Explorer\\iexplore.exe'], '', ''), '-k ', '', ''], [(None, ['Google\\Chrome\\Application\\chrome.exe'], ['google-chrome', 'google-chrome-stable', 'google-chrome-beta', 'chromium-browser'], '"/Applications/Google Chrome.app"'), '--kiosk ', '--user-data-dir=', '--start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run '], [(None, ['Mozilla Firefox\\firefox.exe'], ['firefox'], 'firefox'), '', '-profile ', ''], [(None, ['Safari\\Safari.exe'], '', 'safari'), '', '', '']] if not cust_br: br_path = '' if (not g.platform & g.OS_OSX) and (not cust_br): for path in os_paths: for exe_file in br_config[s.browser][0][br_platform]: if xbmcvfs.exists(OSPJoin(path, exe_file)): br_path = path + exe_file break else: Log('Browser %s not found' % (path + exe_file), Log.DEBUG) if br_path: break if (not xbmcvfs.exists(br_path)) and (not g.platform & g.OS_OSX): return False, nobr_str br_args = br_config[s.browser][3] if kiosk: br_args += br_config[s.browser][1] if appdata and br_config[s.browser][2]: br_args += br_config[s.browser][2] + '"' + OSPJoin(g.DATA_PATH, str(s.browser)) + '" ' if g.platform & g.OS_OSX: if not cust_br: br_path = os_paths + br_config[s.browser][0][3] if br_args.strip(): br_args = '--args ' + br_args br_path += ' %s"%s"' % (br_args, videoUrl) return True, br_path def _getStartupInfo(): si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESHOWWINDOW return si def _ExtPlayback(videoUrl, asin, isAdult, method, fr): waitsec = int(g.addon.getSetting("clickwait")) * 1000 waitprepin = int(g.addon.getSetting("waitprepin")) * 1000 pin = g.addon.getSetting("pin") waitpin = int(g.addon.getSetting("waitpin")) * 1000 pininput = g.addon.getSetting("pininput") == 'true' fullscr = g.addon.getSetting("fullscreen") == 'true' videoUrl += '&playerDebug=true' if s.verbLog else '' xbmc.Player().stop() # xbmc.executebuiltin('ActivateWindow(busydialog)') suc, url = _getCmdLine(videoUrl, asin, method, fr) if not suc: g.dialog.notification(getString(30203), url, xbmcgui.NOTIFICATION_ERROR) return Log('Executing: %s' % url) if g.platform & g.OS_WINDOWS: process = subprocess.Popen(url, startupinfo=_getStartupInfo()) else: args = shlex.split(url) process = subprocess.Popen(args) if g.platform & g.OS_LE: result = 1 while result != 0: p = subprocess.Popen('pgrep chrome > /dev/null', shell=True) p.wait() result = p.returncode if isAdult and pininput: if fullscr: waitsec *= 0.75 else: waitsec = waitprepin xbmc.sleep(int(waitsec)) _Input(keys=pin) waitsec = waitpin if fullscr: xbmc.sleep(int(waitsec)) if s.browser != 0: _Input(keys='f') else: _Input(mousex=-1, mousey=350, click=2) xbmc.sleep(500) _Input(mousex=9999, mousey=350) _Input(mousex=9999, mousey=-1) # xbmc.executebuiltin('Dialog.Close(busydialog)') if s.hasExtRC: return myWindow = _window(process, asin) myWindow.wait() def _AndroidPlayback(asin, trailer): manu = '' if os.access('/system/bin/getprop', os.X_OK): manu = _check_output(['getprop', 'ro.product.manufacturer']) if manu == 'Amazon': pkg = 'com.fivecent.amazonvideowrapper' act = '' url = asin else: pkg = 'com.amazon.avod.thirdpartyclient' act = 'android.intent.action.VIEW' url = g.BaseUrl + '/piv-apk-play?asin=' + asin url += '&playTrailer=T' if trailer == 1 else '' subprocess.Popen(['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Manufacturer: ' + manu]) subprocess.Popen(['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Starting App: %s Video: %s' % (pkg, url)]) Log('Manufacturer: %s' % manu) Log('Starting App: %s Video: %s' % (pkg, url)) if s.verbLog: if os.access('/system/xbin/su', os.X_OK) or os.access('/system/bin/su', os.X_OK): Log('Logcat:\n' + _check_output(['su', '-c', 'logcat -d | grep -i com.amazon.avod'])) Log('Properties:\n' + _check_output(['sh', '-c', 'getprop | grep -iE "(ro.product|ro.build|google)"'])) xbmc.executebuiltin('StartAndroidActivity("%s", "%s", "", "%s")' % (pkg, act, url)) def _IStreamPlayback(asin, name, trailer, isAdult, extern): from .ages import AgeRestrictions vMT = ['Feature', 'Trailer', 'LiveStreaming'][trailer] dRes = 'PlaybackUrls' if trailer == 2 else 'PlaybackUrls,SubtitleUrls,ForcedNarratives' mpaa_str = AgeRestrictions().GetRestrictedAges() + getString(30171) drm_check = g.addon.getSetting("drm_check") == 'true' verifyISA = '{"jsonrpc":"2.0","id":1,"method":"Addons.GetAddonDetails","params":{"addonid":"inputstream.adaptive"}}' if 'error' in xbmc.executeJSONRPC(verifyISA): xbmc.executebuiltin('UpdateAddonRepos', True) xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', True) if 'error' in xbmc.executeJSONRPC(verifyISA): Log('InputStream.Adaptive addon is not installed') _playDummyVid() return True inputstream_helper = Helper('mpd', drm='com.widevine.alpha') if not inputstream_helper.check_inputstream(): Log('No Inputstream Addon found or activated') _playDummyVid() return True cookie = MechanizeLogin() if not cookie: g.dialog.notification(getString(30203), getString(30200), xbmcgui.NOTIFICATION_ERROR) Log('Login error at playback') _playDummyVid() return True mpd, subs = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, vMT=vMT, dRes=dRes, useCookie=cookie), retmpd=True) cj_str = ';'.join(['%s=%s' % (k, v) for k, v in cookie.items()]) opt = '|Content-Type=application%2Fx-www-form-urlencoded&Cookie=' + quote_plus(cj_str) opt += '|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=true' opt += '|JBlicense;hdcpEnforcementResolutionPixels' licURL = getURLData('catalog/GetPlaybackResources', asin, opt=opt, extra=True, vMT=vMT, dRes='Widevine2License', retURL=True) if not mpd: g.dialog.notification(getString(30203), subs, xbmcgui.NOTIFICATION_ERROR) _playDummyVid() return True from xbmcaddon import Addon as KodiAddon is_version = KodiAddon(g.is_addon).getAddonInfo('version') if g.is_addon else '0' is_binary = xbmc.getCondVisibility('System.HasAddon(kodi.binary.instance.inputstream)') if trailer != 2: mpd = re.sub(r'~', '', mpd) if drm_check and (not g.platform & g.OS_ANDROID) and (not is_binary): mpdcontent = getURL(mpd, useCookie=cookie, rjson=False) if 'avc1.4D00' in mpdcontent: # xbmc.executebuiltin('ActivateWindow(busydialog)') return _extrFr(mpdcontent) Log(mpd, Log.DEBUG) if g.KodiK and extern: content = getATVData('GetASINDetails', 'ASINList=' + asin)['titles'][0] ct, Info = g.amz.getInfos(content, False) title = Info['DisplayTitle'] thumb = Info.get('Poster', Info['Thumb']) mpaa_check = str(Info.get('MPAA', mpaa_str)) in mpaa_str or isAdult else: mpaa_check = _getListItem('MPAA') in mpaa_str + mpaa_str.replace(' ', '') or isAdult title = _getListItem('Label') thumb = _getListItem('Art(season.poster)') if not thumb: thumb = _getListItem('Art(tvshow.poster)') if not thumb: thumb = _getListItem('Art(thumb)') if trailer == 1: title += ' (Trailer)' if not title: title = name if mpaa_check and not AgeRestrictions().RequestPin(): return True listitem = xbmcgui.ListItem(label=title, path=mpd) if g.KodiK and extern: listitem.setInfo('video', getInfolabels(Info)) if 'adaptive' in g.is_addon: listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') Log('Using %s Version: %s' % (g.is_addon, is_version)) listitem.setArt({'thumb': thumb}) listitem.setSubtitles(subs) listitem.setProperty('%s.license_type' % g.is_addon, 'com.widevine.alpha') listitem.setProperty('%s.license_key' % g.is_addon, licURL) listitem.setProperty('%s.stream_headers' % g.is_addon, 'user-agent=' + getConfig('UserAgent')) listitem.setProperty('inputstreamaddon', g.is_addon) listitem.setMimeType('application/dash+xml') listitem.setContentLookup(False) player = _AmazonPlayer() player.asin = asin player.cookie = cookie player.content = trailer player.extern = extern player.resolve(listitem) starttime = time.time() while not xbmc.abortRequested and player.running: if player.isPlayingVideo(): player.video_lastpos = player.getTime() if time.time() > starttime + player.interval: starttime = time.time() player.updateStream('PLAY') sleep(1) player.finished() del player return True isAdult = adultstr == '1' amazonUrl = g.BaseUrl + "/dp/" + (name if g.UsePrimeVideo else asin) playable = False fallback = int(g.addon.getSetting("fallback_method")) methodOW = fallback - 1 if forcefb and fallback else s.playMethod videoUrl = "%s/?autoplay=%s" % (amazonUrl, ('trailer' if trailer == 1 else '1')) extern = not xbmc.getInfoLabel('Container.PluginName').startswith('plugin.video.amazon') fr = '' if extern: Log('External Call', Log.DEBUG) while not playable: playable = True if methodOW == 2 and g.platform & g.OS_ANDROID: _AndroidPlayback(asin, trailer) elif methodOW == 3: playable = _IStreamPlayback(asin, name, trailer, isAdult, extern) elif not g.platform & g.OS_ANDROID: _ExtPlayback(videoUrl, asin, isAdult, methodOW, fr) if not playable or isinstance(playable, unicode): if fallback: methodOW = fallback - 1 if isinstance(playable, unicode): fr = playable playable = False else: xbmc.sleep(500) g.dialog.ok(getString(30203), getString(30218)) playable = True if methodOW != 3: _playDummyVid()
def _Input(mousex=0, mousey=0, click=0, keys=None, delay='200'): from common import Globals g = Globals() screenWidth = int(xbmc.getInfoLabel('System.ScreenWidth')) screenHeight = int(xbmc.getInfoLabel('System.ScreenHeight')) keys_only = sc_only = keybd = '' mousex = screenWidth / 2 if mousex == -1 else mousex mousey = screenHeight / 2 if mousey == -1 else mousey spec_keys = {'{EX}': ('!{F4}', 'alt+F4', 'kd:cmd t:q ku:cmd'), '{SPC}': ('{SPACE}', 'space', 't:p'), '{LFT}': ('{LEFT}', 'Left', 'kp:arrow-left'), '{RGT}': ('{RIGHT}', 'Right', 'kp:arrow-right'), '{U}': ('{UP}', 'Up', 'kp:arrow-up'), '{DWN}': ('{DOWN}', 'Down', 'kp:arrow-down'), '{BACK}': ('{BS}', 'BackSpace', 'kp:delete'), '{RET}': ('{ENTER}', 'Return', 'kp:return')} if keys: keys_only = keys for sc in spec_keys: while sc in keys: keys = keys.replace(sc, spec_keys[sc][g.platform - 1]).strip() keys_only = keys_only.replace(sc, '').strip() sc_only = keys.replace(keys_only, '').strip() if g.platform & g.OS_WINDOWS: app = os.path.join(g.PLUGIN_PATH, 'tools', 'userinput.exe') mouse = ' mouse %s %s' % (mousex, mousey) mclk = ' ' + str(click) keybd = ' key %s %s' % (keys, delay) elif g.platform & g.OS_LINUX: app = 'xdotool' mouse = ' mousemove %s %s' % (mousex, mousey) mclk = ' click --repeat %s 1' % click if keys_only: keybd = ' type --delay %s %s' % (delay, keys_only) if sc_only: if keybd: keybd += ' && ' + app keybd += ' key ' + sc_only elif g.platform & g.OS_OSX: app = 'cliclick' mouse = ' m:' if click == 1: mouse = ' c:' elif click == 2: mouse = ' dc:' mouse += '%s,%s' % (mousex, mousey) mclk = '' keybd = ' -w %s' % delay if keys_only: keybd += ' t:%s' % keys_only if keys != keys_only: keybd += ' ' + sc_only if keys: cmd = app + keybd else: cmd = app + mouse if click: cmd += mclk Log('Run command: %s' % cmd) rcode = subprocess.call(cmd, shell=True) if rcode: Log('Returncode: %s' % rcode)
def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main and down_lang > 1: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage(xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ('' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if (p1 == p2): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath('special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % (sub['displayName'].strip(), sub['languageCode']) content = '' Log("Subtitle URL: %s" % (sub['url']), Log.DEBUG) with codecs.open(srtfile, 'w', encoding='utf-8') as srt: # Since dfxp provides no particular metadata and .srt are usually available on amazon's servers, # we try to download the .srt straight away to avoid conversion. Although we avoid it with RTL # languages, since we need to parse them anyway. if (sub['url'].endswith("dfxp")) and ('ar' != sub['languageCode']): subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL(subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang, Log.DEBUG) srt.write(content) continue content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) Log('Output %s' % srtfile, Log.DEBUG) # Apply a bunch of regex to the content instead of line-by-line to save computation time content = re.sub(r'<(|/)span[^>]*>', r'<\1i>', content) # Using (|<search>) instead of ()? to avoid py2.7 empty matching error content = re.sub(r'([0-9]{2}:[0-9]{2}:[0-9]{2})\.', r'\1,', content) # SRT-like timestamps content = re.sub(r'\s*<(?:tt:)?br\s*/>\s*', '\n', content) # Replace <br/> with actual new lines # Convert dfxp or ttml2 to srt num = 0 for tt in re.compile(r'<(?:tt:)?p begin="([^"]+)"[^>]*end="([^"]+)"[^>]*>\s*(.*?)\s*</(?:tt:)?p>', re.DOTALL).findall(content): text = tt[2] # Embed RTL and change the punctuation where needed if 'ar' == sub['languageCode']: from unicodedata import lookup text = re.sub('^', lookup('RIGHT-TO-LEFT EMBEDDING'), text, flags=re.MULTILINE) text = text.replace('?', '؟').replace(',', '،') for ec in escape_chars: text = text.replace(ec[0], ec[1]) num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt[0], tt[1], text)) Log('Conversion finished', Log.DEBUG) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str(hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)
def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle()
def PlayVideo(name, asin, adultstr, trailer, forcefb=0): g = Globals() s = Settings() def _check_output(*popenargs, **kwargs): p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) out, err = p.communicate() retcode = p.poll() if retcode != 0: c = kwargs.get("args") if c is None: c = popenargs[0] e = subprocess.CalledProcessError(retcode, c) e.output = str(out) + str(err) Log(e, Log.ERROR) return out.strip() def _playDummyVid(): dummy_video = OSPJoin(g.PLUGIN_PATH, 'resources', 'dummy.avi') xbmcplugin.setResolvedUrl(g.pluginhandle, True, xbmcgui.ListItem(path=dummy_video)) Log('Playing Dummy Video', Log.DEBUG) xbmc.Player().stop() return def _extrFr(data): fps_string = re.compile('frameRate="([^"]*)').findall(data)[0] fr = round(eval(fps_string + '.0'), 3) return str(fr).replace('.0', '') def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = [ sub['url'] for sub in data['subtitles'] if 'url' in sub.keys() ] if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str( hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][ 0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return ('http://{}/mpd/{}'.format(s.proxyaddress, quote_plus(urlset['url'])), subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217) def _getCmdLine(videoUrl, asin, method, fr): scr_path = g.addon.getSetting("scr_path") br_path = g.addon.getSetting("br_path").strip() scr_param = g.addon.getSetting("scr_param").strip() kiosk = g.addon.getSetting("kiosk") == 'true' appdata = g.addon.getSetting("ownappdata") == 'true' cust_br = g.addon.getSetting("cust_path") == 'true' nobr_str = getString(30198) frdetect = g.addon.getSetting("framerate") == 'true' if method == 1: if not xbmcvfs.exists(scr_path): return False, nobr_str if frdetect: suc, fr = _ParseStreams( *getURLData('catalog/GetPlaybackResources', asin, extra=True, useCookie=True)) if not fr else (True, fr) if not suc: return False, fr else: fr = '' return True, scr_path + ' ' + scr_param.replace('{f}', fr).replace( '{u}', videoUrl) br_platform = (g.platform & -g.platform).bit_length() os_paths = [ None, ('C:\\Program Files\\', 'C:\\Program Files (x86)\\'), ('/usr/bin/', '/usr/local/bin/'), 'open -a ' ][br_platform] # path(0,win,lin,osx), kiosk, profile, args br_config = [ [(None, ['Internet Explorer\\iexplore.exe'], '', ''), '-k ', '', ''], [(None, ['Google\\Chrome\\Application\\chrome.exe'], [ 'google-chrome', 'google-chrome-stable', 'google-chrome-beta', 'chromium-browser' ], '"/Applications/Google Chrome.app"'), '--kiosk ', '--user-data-dir=', '--start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run ' ], [(None, ['Mozilla Firefox\\firefox.exe'], ['firefox'], 'firefox'), '', '-profile ', ''], [(None, ['Safari\\Safari.exe'], '', 'safari'), '', '', ''] ] if not cust_br: br_path = '' if (not g.platform & g.OS_OSX) and (not cust_br): for path in os_paths: for exe_file in br_config[s.browser][0][br_platform]: if xbmcvfs.exists(OSPJoin(path, exe_file)): br_path = path + exe_file break else: Log('Browser %s not found' % (path + exe_file), Log.DEBUG) if br_path: break if (not xbmcvfs.exists(br_path)) and (not g.platform & g.OS_OSX): return False, nobr_str br_args = br_config[s.browser][3] if kiosk: br_args += br_config[s.browser][1] if appdata and br_config[s.browser][2]: br_args += br_config[s.browser][2] + '"' + OSPJoin( g.DATA_PATH, str(s.browser)) + '" ' if g.platform & g.OS_OSX: if not cust_br: br_path = os_paths + br_config[s.browser][0][3] if br_args.strip(): br_args = '--args ' + br_args br_path += ' %s"%s"' % (br_args, videoUrl) return True, br_path def _getStartupInfo(): si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESHOWWINDOW return si def _ExtPlayback(videoUrl, asin, isAdult, method, fr): waitsec = int(g.addon.getSetting("clickwait")) * 1000 waitprepin = int(g.addon.getSetting("waitprepin")) * 1000 pin = g.addon.getSetting("pin") waitpin = int(g.addon.getSetting("waitpin")) * 1000 pininput = g.addon.getSetting("pininput") == 'true' fullscr = g.addon.getSetting("fullscreen") == 'true' videoUrl += '&playerDebug=true' if s.verbLog else '' xbmc.Player().stop() # xbmc.executebuiltin('ActivateWindow(busydialog)') suc, url = _getCmdLine(videoUrl, asin, method, fr) if not suc: g.dialog.notification(getString(30203), url, xbmcgui.NOTIFICATION_ERROR) return Log('Executing: %s' % url) if g.platform & g.OS_WINDOWS: process = subprocess.Popen(url, startupinfo=_getStartupInfo()) else: args = shlex.split(url) process = subprocess.Popen(args) if g.platform & g.OS_LE: result = 1 while result != 0: p = subprocess.Popen('pgrep chrome > /dev/null', shell=True) p.wait() result = p.returncode if isAdult and pininput: if fullscr: waitsec *= 0.75 else: waitsec = waitprepin xbmc.sleep(int(waitsec)) _Input(keys=pin) waitsec = waitpin if fullscr: xbmc.sleep(int(waitsec)) if s.browser != 0: _Input(keys='f') else: _Input(mousex=-1, mousey=350, click=2) xbmc.sleep(500) _Input(mousex=9999, mousey=350) _Input(mousex=9999, mousey=-1) # xbmc.executebuiltin('Dialog.Close(busydialog)') if s.hasExtRC: return myWindow = _window(process, asin) myWindow.wait() def _AndroidPlayback(asin, trailer): manu = '' if os.access('/system/bin/getprop', os.X_OK): manu = _check_output(['getprop', 'ro.product.manufacturer']) if manu == 'Amazon': pkg = 'com.fivecent.amazonvideowrapper' act = '' url = asin else: pkg = 'com.amazon.avod.thirdpartyclient' act = 'android.intent.action.VIEW' url = g.BaseUrl + '/piv-apk-play?asin=' + asin url += '&playTrailer=T' if trailer == 1 else '' subprocess.Popen( ['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Manufacturer: ' + manu]) subprocess.Popen([ 'log', '-p', 'v', '-t', 'Kodi-Amazon', 'Starting App: %s Video: %s' % (pkg, url) ]) Log('Manufacturer: %s' % manu) Log('Starting App: %s Video: %s' % (pkg, url)) if s.verbLog: if os.access('/system/xbin/su', os.X_OK) or os.access( '/system/bin/su', os.X_OK): Log('Logcat:\n' + _check_output( ['su', '-c', 'logcat -d | grep -i com.amazon.avod'])) Log('Properties:\n' + _check_output([ 'sh', '-c', 'getprop | grep -iE "(ro.product|ro.build|google)"' ])) xbmc.executebuiltin('StartAndroidActivity("%s", "%s", "", "%s")' % (pkg, act, url)) def _IStreamPlayback(asin, name, trailer, isAdult, extern): from .ages import AgeRestrictions vMT = ['Feature', 'Trailer', 'LiveStreaming'][trailer] dRes = 'PlaybackUrls' if trailer == 2 else 'PlaybackUrls,SubtitleUrls,ForcedNarratives' mpaa_str = AgeRestrictions().GetRestrictedAges() + getString(30171) drm_check = g.addon.getSetting("drm_check") == 'true' verifyISA = '{"jsonrpc":"2.0","id":1,"method":"Addons.GetAddonDetails","params":{"addonid":"inputstream.adaptive"}}' if 'error' in xbmc.executeJSONRPC(verifyISA): xbmc.executebuiltin('UpdateAddonRepos', True) xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', True) if 'error' in xbmc.executeJSONRPC(verifyISA): Log('InputStream.Adaptive addon is not installed') _playDummyVid() return True inputstream_helper = Helper('mpd', drm='com.widevine.alpha') if not inputstream_helper.check_inputstream(): Log('No Inputstream Addon found or activated') _playDummyVid() return True cookie = MechanizeLogin() if not cookie: g.dialog.notification(getString(30203), getString(30200), xbmcgui.NOTIFICATION_ERROR) Log('Login error at playback') _playDummyVid() return True mpd, subs = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, vMT=vMT, dRes=dRes, useCookie=cookie, proxyEndpoint='gpr'), retmpd=True) cj_str = ';'.join(['%s=%s' % (k, v) for k, v in cookie.items()]) opt = '|Content-Type=application%2Fx-www-form-urlencoded&Cookie=' + quote_plus( cj_str) opt += '|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=true' opt += '|JBlicense;hdcpEnforcementResolutionPixels' licURL = getURLData('catalog/GetPlaybackResources', asin, opt=opt, extra=True, vMT=vMT, dRes='Widevine2License', retURL=True) if not mpd: g.dialog.notification(getString(30203), subs, xbmcgui.NOTIFICATION_ERROR) _playDummyVid() return True from xbmcaddon import Addon as KodiAddon is_version = KodiAddon( g.is_addon).getAddonInfo('version') if g.is_addon else '0' is_binary = xbmc.getCondVisibility( 'System.HasAddon(kodi.binary.instance.inputstream)') if (not s.audioDescriptions) and (trailer != 2): mpd = re.sub(r'(~|%7E)', '', mpd) if drm_check and (not g.platform & g.OS_ANDROID) and (not is_binary): mpdcontent = getURL(mpd, useCookie=cookie, rjson=False) if 'avc1.4D00' in mpdcontent: # xbmc.executebuiltin('ActivateWindow(busydialog)') return _extrFr(mpdcontent) Log(mpd, Log.DEBUG) if g.KodiK and extern: content = getATVData('GetASINDetails', 'ASINList=' + asin)['titles'][0] ct, Info = g.amz.getInfos(content, False) title = Info['DisplayTitle'] thumb = Info.get('Poster', Info['Thumb']) mpaa_check = str(Info.get('MPAA', mpaa_str)) in mpaa_str or isAdult else: mpaa_check = _getListItem('MPAA') in mpaa_str + mpaa_str.replace( ' ', '') or isAdult title = _getListItem('Label') thumb = _getListItem('Art(season.poster)') if not thumb: thumb = _getListItem('Art(tvshow.poster)') if not thumb: thumb = _getListItem('Art(thumb)') if trailer == 1: title += ' (Trailer)' if not title: title = name if mpaa_check and not AgeRestrictions().RequestPin(): return True listitem = xbmcgui.ListItem(label=title, path=mpd) if g.KodiK and extern: listitem.setInfo('video', getInfolabels(Info)) if 'adaptive' in g.is_addon: listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') Log('Using %s Version: %s' % (g.is_addon, is_version)) listitem.setArt({'thumb': thumb}) listitem.setSubtitles(subs) listitem.setProperty('%s.license_type' % g.is_addon, 'com.widevine.alpha') listitem.setProperty('%s.license_key' % g.is_addon, licURL) listitem.setProperty('%s.stream_headers' % g.is_addon, 'user-agent=' + getConfig('UserAgent')) listitem.setProperty('inputstreamaddon', g.is_addon) listitem.setMimeType('application/dash+xml') listitem.setContentLookup(False) player = _AmazonPlayer() player.asin = asin player.cookie = cookie player.content = trailer player.extern = extern player.resolve(listitem) starttime = time.time() while not xbmc.abortRequested and player.running: if player.isPlayingVideo(): player.video_lastpos = player.getTime() if time.time() > starttime + player.interval: starttime = time.time() player.updateStream('PLAY') sleep(1) player.finished() del player return True isAdult = adultstr == '1' amazonUrl = g.BaseUrl + "/dp/" + (name if g.UsePrimeVideo else asin) playable = False fallback = int(g.addon.getSetting("fallback_method")) methodOW = fallback - 1 if forcefb and fallback else s.playMethod videoUrl = "%s/?autoplay=%s" % (amazonUrl, ('trailer' if trailer == 1 else '1')) extern = not xbmc.getInfoLabel('Container.PluginName').startswith( 'plugin.video.amazon') fr = '' if extern: Log('External Call', Log.DEBUG) while not playable: playable = True if methodOW == 2 and g.platform & g.OS_ANDROID: _AndroidPlayback(asin, trailer) elif methodOW == 3: playable = _IStreamPlayback(asin, name, trailer, isAdult, extern) elif not g.platform & g.OS_ANDROID: _ExtPlayback(videoUrl, asin, isAdult, methodOW, fr) if not playable or isinstance(playable, unicode): if fallback: methodOW = fallback - 1 if isinstance(playable, unicode): fr = playable playable = False else: xbmc.sleep(500) g.dialog.ok(getString(30203), getString(30218)) playable = True if methodOW != 3: _playDummyVid()
def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage( xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ( '' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if ( p1 == p2 ): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath( 'special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % ( sub['displayName'].strip(), sub['languageCode']) content = '' with codecs.open(srtfile, 'w', encoding='utf-8') as srt: num = 0 # Since .srt are available on amazon's servers, we strip the default extension and try downloading it just once subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL( subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang) srt.write(content) else: content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) for tt in re.compile('<tt:p(.*)').findall(content): tt = re.sub('<tt:br[^>]*>', '\n', tt) tt = re.search( r'begin="([^"]*).*end="([^"]*).*>([^<]*).', tt) subtext = tt.group(3) for ec in escape_chars: subtext = subtext.replace(ec[0], ec[1]) if tt: num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt.group(1), tt.group(2), subtext)) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str( hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][ 0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)