def open_page( plugin, url, params={ "box_mac": ''.join(re.findall('..', '%012x' % uuid.getnode())), "box_user": Settings.get_string("email") }, search_query=None, base_url=None): items_m3u = None items_et = None if search_query: params.update({"search": search_query}) else: params.update({"search": None}) if Settings.get_string("mac") != "default": params.update({"box_mac": Settings.get_string("mac")}) url_constructor = urljoin_partial(base_url) resp = urlquick.get(url_constructor(url), params=params, max_age=1, headers={ "Accept": "text/xml" }).text if '<?xml version="1.0"' in resp: return open_xml_page(page=resp, base_url=base_url) elif '"title":' in resp: return open_json_page(plugin, page=resp, base_url=base_url) elif '#EXTINF:' in resp: return open_m3u_playlist(playlist=resp, base_url=base_url)
def qualityFilter(config): return (config.get("resolution", "hd") == ["4k", "hd", "sd"][Settings.get_int("resolution")] and config.get("video_codec", "h265") == [ "dvh265", "h265", "vp9", "h264" ][Settings.get_int("video_codec")] and config.get("dynamic_range", "sdr") == ["dv", "hdr10", "sdr"][Settings.get_int("dynamic_range")] and config.get("audio_channel", "stereo") == ["stereo", "dolby51"][Settings.get_int("audio_channel")] and config.get("audio_codec", "aac") == ["ec3", "aac"][Settings.get_int("audio_codec")])
def doLogin(self): with PersistentDict("userdata.pickle") as db: try: username = Settings.get_string( "username", "plugin.video.jiotv") or db.get("username") or Dialog( ).input("Username (MobileNo / Email)") password = Settings.get_string( "password", "plugin.video.jiotv") or db.get( "password") or Dialog().input("Password") except RuntimeError: username = Dialog().input("Username (MobileNo / Email)") password = Dialog().input("Password") if username and password: body = { "identifier": username if '@' in username else "+91" + username, "password": password, "rememberUser": "******", "upgradeAuth": "Y", "returnSessionDetails": "T", "deviceInfo": { "consumptionDeviceName": "Jio", "info": { "type": "android", "platform": { "name": "vbox86p", "version": "8.0.0" }, "androidId": "6fcadeb7b4b10d77" } } } resp = urlquick.post( "https://api.jio.com/v3/dip/user/unpw/verify", json=body, headers={ "x-api-key": "l7xx75e822925f184370b2e25170c5d5820a" }, verify=False, raise_for_status=False).json() if resp.get("ssoToken"): db["data"] = resp Script.notify("Login Successful", "You have been logged in successfully") else: Script.notify( "Login Failed", "Double check you username and password and try again") else: Script.notify("Login Required", "Please login with you Jio credentials")
def m3ugen(plugin): channels = urlquick.get(CHANNELS_SRC).json().get("result") m3ustr = "#EXTM3U x-tvg-url=\"%s\"" % EPG_SRC for i, channel in enumerate(channels): lang = LANG_MAP[channel.get("channelLanguageId")] genre = GENRE_MAP[channel.get("channelCategoryId")] if not Settings.get_boolean(lang): continue group = lang + ";" + genre _play_url = PLAY_URL + \ "channel_id={0}".format(channel.get("channel_id")) catchup = "" if channel.get("isCatchupAvailable"): catchup = ' catchup="vod" catchup-source="{0}channel_id={1}&showtime={{H}}{{M}}{{S}}&srno={{Y}}{{m}}{{d}}" catchup-days="7"'.format( PLAY_URL, channel.get("channel_id")) m3ustr += M3U_CHANNEL.format( tvg_id=channel.get("channel_id"), channel_name=channel.get("channel_name"), group_title=group, tvg_chno=int(channel.get("channel_order", i)) + 1, tvg_logo=IMG_CATCHUP + channel.get("logoUrl", ""), catchup=catchup, play_url=_play_url, ) with open(M3U_SRC, "w+") as f: f.write(m3ustr.replace(u'\xa0', ' ').encode('utf-8').decode('utf-8')) Script.notify("JioTV", "Playlist updated. Restart to apply.")
def fltr(x): fby = by.lower()[:-1] if fby == "genre": return x.get(fby) == category_id and Settings.get_boolean( x.get("language")) else: return x.get(fby) == category_id
def play(plugin, channel_id, showtime=None, srno=None): if showtime is None and Settings.get_boolean("extra"): with open(EXTRA_CHANNELS, "r") as f: extra = json.load(f) if extra.get(str(channel_id)): if extra.get(str(channel_id)).get("ext"): return extra.get(str(channel_id)).get("ext") return PLAY_EX_URL + extra.get(str(channel_id)).get("data") rjson = { "channel_id": int(channel_id), "stream_type": "Seek" } if showtime and srno: rjson["showtime"] = showtime rjson["srno"] = srno rjson["stream_type"] = "Catchup" resp = urlquick.post(GET_CHANNEL_URL, json=rjson).json() art = {} art["thumb"] = art["icon"] = IMG_CATCHUP + \ resp.get("result", "").split("/")[-1].replace(".m3u8", ".jpg") params = getTokenParams() return Listitem().from_dict(**{ "label": plugin._title, "art": art, "callback": resp.get("result", "") + "?" + urlencode(params), "properties": { "IsPlayable": True, "inputstream": "inputstream.adaptive", "inputstream.adaptive.stream_headers": "User-Agent=KAIOS", "inputstream.adaptive.manifest_type": "hls", "inputstream.adaptive.license_key": urlencode(params) + "|" + urlencode(getHeaders()) + "|R{SSM}|", } })
def show_category(plugin, category_id, by): resp = urlquick.get(CHANNELS_SRC).json().get("result") def fltr(x): fby = by.lower()[:-1] if fby == "genre": return GENRE_MAP[x.get("channelCategoryId")] == category_id and Settings.get_boolean(LANG_MAP[x.get("channelLanguageId")]) else: return LANG_MAP[x.get("channelLanguageId")] == category_id for each in filter(fltr, resp): if each.get("channelIdForRedirect") and not Settings.get_boolean("extra"): continue litm = Listitem.from_dict(**{ "label": each.get("channel_name"), "art": { "thumb": IMG_CATCHUP + each.get("logoUrl"), "icon": IMG_CATCHUP + each.get("logoUrl"), "fanart": IMG_CATCHUP + each.get("logoUrl"), "clearlogo": IMG_CATCHUP + each.get("logoUrl"), "clearart": IMG_CATCHUP + each.get("logoUrl"), }, "callback": play, "params": { "channel_id": each.get("channel_id") } }) if each.get("isCatchupAvailable"): litm.context.container(show_epg, "Catchup", 0, each.get("channel_id")) yield litm
def __init__(self, proxy): self.proxy = proxy p = urlparse(proxy.path) self.path = p.path self.params = parse_qs(p.query) play_url = self.path.endswith('master.m3u8') m3u8_url = self.path.endswith('.m3u8') ts_url = self.path.endswith('.ts') key_url = self.path.endswith('.key') self.ishls = 'packagerx' in self.path self.channel_name = self.path.split( '/')[3] if self.ishls else self.path.split('/')[2] self.maxq = 'maxq' in self.params and int(self.params['maxq'][0]) self.hlsrx = '' if not self.ishls else "/"+self.path.split('/')[2] self.quality = qmap[Settings.get_string('quality')] try: if play_url: self.getMaster() elif m3u8_url: self.getM3U8() elif key_url: self.resolveKey() elif ts_url: self.resolveTS() else: Script.log("Resource not found by proxy", lvl=Script.INFO) self.proxy.send_error(404, "Not Found") except Exception, e: Script.log(e, lvl=Script.INFO) if(self.proxy): self.proxy.send_error(500, "Internal Server Error") self.proxy.wfile.write(str(e).encode("utf-8"))
def fltr(x): fby = by.lower()[:-1] if fby == "genre": return GENRE_MAP[x.get( "channelCategoryId")] == category_id and Settings.get_boolean( LANG_MAP[x.get("channelLanguageId")]) else: return LANG_MAP[x.get("channelLanguageId")] == category_id
def doLogin(self): try: username = Settings.get_string( "username", "plugin.video.jiotvx") or Dialog().input( "Username (MobileNo / Email)") password = Settings.get_string( "password", "plugin.video.jiotvx") or Dialog().input("Password") except RuntimeError: username = Dialog().input("Username (MobileNo / Email)") password = Dialog().input("Password") if username and password: body = { "identifier": username if "@" in username else "+91" + username, "password": password, "rememberUser": "******", "upgradeAuth": "Y", "returnSessionDetails": "T", "deviceInfo": { "consumptionDeviceName": "unknown sdk_google_atv_x86", "info": { "type": "android", "platform": { "name": "generic_x86", "version": "8.1.0" }, "androidId": str(uuid4()) } } } resp = self.post( "https://api.jio.com/v3/dip/user/unpw/verify", json=body, headers={"x-api-key": "l7xx75e822925f184370b2e25170c5d5820a"}) if resp.get("ssoToken"): with PersistentDict("userdata.pickle") as db: db["data"] = resp else: Script.notify( "Login Failed", "Double check you username and password and try again") else: Script.notify("Login Required", "Please login with you Jio credentials")
def m3ugen(plugin): channels = urlquick.get(CHANNELS_SRC).json().get("result") m3ustr = "#EXTM3U x-tvg-url=\"%s\"\n" % EPG_SRC for i, channel in enumerate(channels): lang = LANG_MAP[channel.get("channelLanguageId")] genre = GENRE_MAP[channel.get("channelCategoryId")] if not Settings.get_boolean(lang) and Settings.get_boolean("uselang"): continue group = lang + ";" + genre _play_url = PLAY_URL + \ hexlify(dumps({"channel_id": channel.get("channel_id")})) m3ustr += "\n\n#EXTINF:0 tvg-id=\"%d\" tvg-name=\"%s\" group-title=\"%s\" tvg-chno=\"%d\" tvg-logo=\"%s\",%s\n%s" % ( channel.get("channel_id"), channel.get("channel_name"), group, int(channel.get("channel_order", i)) + 1, IMG_CATCHUP + channel.get("logoUrl", ""), channel.get("channel_name"), _play_url) with open(M3U_SRC, "w+") as f: f.write(m3ustr.replace(u'\xa0', ' ').encode('utf-8')) Script.notify("JioTV", "Playlist updated. Restart to apply.")
def serveForever(handler): try: handler.serve_forever() except Exception as e: Script.log(e, lvl=Script.DEBUG) pass ThreadingTCPServer.allow_reuse_address = True _PORT = 48996 handler = ThreadingTCPServer(("", _PORT), proxy.JioTVProxy) t = threading.Thread(target=serveForever, args=(handler, )) t.setDaemon(True) t.start() if not Settings.get_boolean("popup"): xbmcgui.Dialog().ok( "JioTV Notification", "Now you can create your custom playlist from BotAllen Dashboard. [CR]Find out more at [B]https://botallen.com/#dashboard[/B] [CR][CR]If you like this add-on then consider donating from [B]https://botallen.com/#donate[/B] [CR][CR]Github: [B]https://github.com/botallen/repository.botallen[/B] [CR]Discord: [B]https://botallen.com/discord[/B] [CR][CR][I]You can disable this popup from settings[/I]" ) if Settings.get_boolean("m3ugen"): executebuiltin( "RunPlugin(plugin://plugin.video.jiotv/resources/lib/main/m3ugen/?notify=no)" ) monitor = Monitor() while not monitor.abortRequested(): if monitor.waitForAbort(10): handler.shutdown() handler.server_close()
import SocketServer import threading from xbmc import Monitor from kodi_six import xbmcgui def serveForever(handler): try: handler.serve_forever() except Exception as e: Script.log(e, lvl=Script.DEBUG) pass SocketServer.ThreadingTCPServer.allow_reuse_address = True _PORT = 48996 handler = SocketServer.ThreadingTCPServer(("", _PORT), proxy.JioTVProxy) t = threading.Thread(target=serveForever, args=(handler,)) t.setDaemon(True) t.start() if not Settings.get_boolean("popup"): xbmcgui.Dialog().ok("JioTV Notification", "Now you can create your custom playlist from BotAllen Dashboard. [CR]Find out more at [B]https://botallen.com/#dashboard[/B] [CR][CR]If you like this add-on then consider donating from [B]https://botallen.com/#donate[/B] [CR][CR]Github: [B]https://github.com/botallen/repository.botallen[/B] [CR]Discord: [B]https://botallen.com/discord[/B] [CR][CR][I]You can disable this popup from settings[/I]") monitor = Monitor() while not monitor.abortRequested(): if monitor.waitForAbort(10): handler.shutdown() handler.server_close() break
def login(plugin): username = Settings.get_string("username") or keyboard( "Username (MobileNo / Email)") password = Settings.get_string("password") or keyboard("Password", hidden=True) ULogin(username, password)
def _findPlayback(playBackSets, lang=None, ask=False): selected = None index = -1 options = [] quality = {"4k": 0, "hd": 1, "sd": 2} for each in playBackSets: config = { k: v for d in map(lambda x: dict([x.split(":")]), each.get("tagsCombination", "a:b").split(";")) for k, v in d.items() } Script.log(f"Checking combination {config} with language {lang}", lvl=Script.DEBUG) if config.get("encryption", "") in ["plain", "widevine"] and config.get( "package", "") in ["hls", "dash"]: if lang and config.get("language") and config.get( "language", "") != lang: continue config["playback"] = (each.get("playbackUrl"), each.get("licenceUrl"), "mpd" if config.get("package") == "dash" else "hls") if selected is None: selected = config["playback"] if config.get("ladder"): del config["ladder"] if config not in options: options.append(config) options.sort( key=lambda x: str(quality.get(x.get("resolution", "sd")) or "")) if len(options) > 0: if Settings.get_string("playback_select") == "Ask" or ask: index = Dialog().select( "Playback Quality", list( map( lambda x: "Video: {0} - {1} - {2} - {3} | Audio: {4} - {5} | {6}" .format( x.get("resolution", "").upper(), x.get("dynamic_range", "").upper(), x.get("video_codec", "").upper(), x.get("container", "").upper(), x.get("audio_channel", "").upper(), x.get("audio_codec", "").upper(), "Non-DRM" if x.get("encryption", "plain") == "plain" else "DRM"), options))) if index == -1: return (None, None, None) else: options = list(filter(qualityFilter, options)) if len(options) > 0: index = 0 if len(options) > 0: Script.log("Selected Config {0}".format(options[index])) selected = options[index].get("playback") if selected is None: selected = (playBackSets[0].get("playbackUrl"), playBackSets[0].get("licenceUrl"), "hls" if ".m3u8" in playBackSets[0].get("playbackUrl") else "mpd") Script.log("No stream found for desired config. Using %s" % playBackSets[0].get("playbackUrl"), lvl=Script.INFO) return selected