Skip to content

Commit

Permalink
Support for inputstream adaptive 20.3.3 (works only on kodi Nexus)
Browse files Browse the repository at this point in the history
  • Loading branch information
Geletinousamigo committed Feb 16, 2023
1 parent 17fbd14 commit ac896c8
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 5,429 deletions.
1 change: 0 additions & 1 deletion addon.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<import addon="script.module.codequick" version="1.0.2"/>
<import addon="script.module.inputstreamhelper" version="0.5.10"/>
<import addon="inputstream.adaptive" minversion="2.6.6"/>
<import addon="script.module.m3u8" version="0.5.4"/>
<import addon="repository.botallen" version="2.0.0"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon.py">
Expand Down
5,354 changes: 0 additions & 5,354 deletions resources/extra/channels.json

This file was deleted.

12 changes: 6 additions & 6 deletions resources/lib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
PLAY_URL = "plugin://plugin.video.jiotv/resources/lib/main/play/?"
PLAY_EX_URL = "plugin://plugin.video.jiotv/resources/lib/main/play_ex/?_pickle_="
FEATURED_SRC = "https://tv.media.jio.com/apis/v1.6/getdata/featurednew?start=0&limit=30&langId=6"
EXTRA_CHANNELS = os.path.join(translatePath(
ADDON.getAddonInfo("path")), "resources", "extra", "channels.json")
CHANNELS_SRC = "http://jiotv.data.cdn.jio.com/apis/v1.3/getMobileChannelList/get/?os=android&devicetype=phone&version=6.0.9"
GET_CHANNEL_URL = "https://tv.media.jio.com/apis/v1.5/getchannelurl/getchannelurl?langId=6&userLanguages=All"
""" EXTRA_CHANNELS = os.path.join(translatePath(
ADDON.getAddonInfo("path")), "resources", "extra", "channels.json") """
CHANNELS_SRC = "https://jiotv.data.cdn.jio.com/apis/v3.0/getMobileChannelList/get/?langId=6&os=android&devicetype=phone&usertype=JIO&version=290&langId=6"
GET_CHANNEL_URL = "https://jiotvapi.media.jio.com/playback/apis/v1/geturl?langId=6"
CATCHUP_SRC = "http://jiotv.data.cdn.jio.com/apis/v1.3/getepg/get?offset={0}&channel_id={1}&langId=6"
M3U_SRC = os.path.join(translatePath(
ADDON.getAddonInfo("profile")), "playlist.m3u")
Expand Down Expand Up @@ -161,7 +161,7 @@
}
]
LANG_MAP = {6: "English", 1: "Hindi", 2: "Marathi", 3: "Punjabi", 4: "Urdu", 5: "Bengali", 7: "Malayalam", 8: "Tamil",
9: "Gujarati", 10: "Odia", 11: "Telugu", 12: "Bhojpuri", 13: "Kannada", 14: "Assamese", 15: "Nepali", 16: "French"}
9: "Gujarati", 10: "Odia", 11: "Telugu", 12: "Bhojpuri", 13: "Kannada", 14: "Assamese", 15: "Nepali", 16: "French", 18: "Manipuri"}
GENRE_MAP = {8: "Sports", 5: "Entertainment", 6: "Movies", 12: "News", 13: "Music", 7: "Kids", 9: "Lifestyle",
10: "Infotainment", 15: "Devotional", 16: "Business", 17: "Educational", 18: "Shopping", 19: "JioDarshan"}
10: "Infotainment", 15: "Devotional", 16: "Business", 17: "Educational", 18: "TestChannels", 19: "JioDarshan"}
CONFIG = {"Genres": GENRE_CONFIG, "Languages": LANGUAGE_CONFIG}
98 changes: 40 additions & 58 deletions resources/lib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
from codequick.storage import PersistentDict

# add-on imports
from resources.lib.utils import getTokenParams, getHeaders, isLoggedIn, login as ULogin, logout as ULogout, check_addon, sendOTP, get_local_ip
from resources.lib.constants import GET_CHANNEL_URL, PLAY_EX_URL, EXTRA_CHANNELS, GENRE_MAP, LANG_MAP, FEATURED_SRC, CONFIG, CHANNELS_SRC, IMG_CATCHUP, PLAY_URL, IMG_CATCHUP_SHOWS, CATCHUP_SRC, M3U_SRC, EPG_SRC, M3U_CHANNEL
from resources.lib.utils import getHeaders, isLoggedIn, login as ULogin, logout as ULogout, check_addon, sendOTP, get_local_ip
from resources.lib.constants import GET_CHANNEL_URL, GENRE_MAP, LANG_MAP, FEATURED_SRC, CONFIG, CHANNELS_SRC, IMG_CATCHUP, PLAY_URL, IMG_CATCHUP_SHOWS, CATCHUP_SRC, M3U_SRC, EPG_SRC, M3U_CHANNEL

# additional imports
import urlquick
from urllib.parse import urlencode
import inputstreamhelper
import json
import m3u8
from time import time, sleep
from datetime import datetime, timedelta, date

Expand Down Expand Up @@ -58,7 +57,7 @@ def show_featured(plugin, id=None):
"usergroup": "tvYR7NSNn7rymo3F",
"os": "android",
"devicetype": "phone",
"versionCode": "226"
"versionCode": "290"
}, max_age=-1).json()
for each in resp.get("featuredNewData", []):
if id:
Expand All @@ -77,8 +76,8 @@ def show_featured(plugin, id=None):
'originaltitle': child.get("showname"),
"tvshowtitle": child.get("showname"),
"genre": child.get("showGenre"),
"plot": child.get("description"),
"episodeguide": child.get("episode_desc"),
"plot": child.get("episode_desc"),
"episodeguide": child.get("description"),
"episode": 0 if child.get("episode_num") == -1 else child.get("episode_num"),
"cast": child.get("starCast", "").split(', '),
"director": child.get("director"),
Expand Down Expand Up @@ -110,7 +109,10 @@ def show_featured(plugin, id=None):
info_dict["params"] = {
"channel_id": child.get("channel_id"),
"showtime": child.get("showtime", "").replace(":", ""),
"srno": datetime.fromtimestamp(int(child.get("startEpoch", 0)*.001)).strftime('%Y%m%d')
"srno": datetime.fromtimestamp(int(child.get("startEpoch", 0)*.001)).strftime('%Y%m%d'),
"programId": child.get("srno", ""),
"begin": datetime.utcfromtimestamp(int(child.get("startEpoch", 0)*.001)).strftime('%Y%m%dT%H%M%S'),
"end": datetime.utcfromtimestamp(int(child.get("endEpoch", 0)*.001)).strftime('%Y%m%dT%H%M%S')
}
yield Listitem.from_dict(**info_dict)
else:
Expand Down Expand Up @@ -154,9 +156,7 @@ def fltr(x):
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
for each in filter(fltr, resp):
litm = Listitem.from_dict(**{
"label": each.get("channel_name"),
"art": {
Expand Down Expand Up @@ -216,7 +216,10 @@ def show_epg(plugin, day, channel_id):
"params": {
"channel_id": each.get("channel_id"),
"showtime": None if islive else each.get("showtime", "").replace(":", ""),
"srno": None if islive else datetime.fromtimestamp(int(each.get("startEpoch", 0)*.001)).strftime('%Y%m%d')
"srno": None if islive else datetime.fromtimestamp(int(each.get("startEpoch", 0)*.001)).strftime('%Y%m%d'),
"programId": None if islive else each.get("srno", ""),
"begin": None if islive else datetime.utcfromtimestamp(int(each.get("startEpoch", 0)*.001)).strftime('%Y%m%dT%H%M%S'),
"end": None if islive else datetime.utcfromtimestamp(int(each.get("endEpoch", 0)*.001)).strftime('%Y%m%dT%H%M%S')
}
})
if int(day) == 0:
Expand All @@ -233,49 +236,15 @@ def show_epg(plugin, day, channel_id):
})


@Resolver.register
@isLoggedIn
def play_ex(plugin, dt=None):
is_helper = inputstreamhelper.Helper(
dt.get("proto", "mpd"), drm=dt.get("drm"))
if is_helper.check_inputstream():
licenseUrl = dt.get("lUrl") and dt.get("lUrl").replace("{HEADERS}", urlencode(
getHeaders())).replace("{TOKEN}", urlencode(getTokenParams()))
art = {}
if dt.get("default_logo"):
art['thumb'] = art['icon'] = IMG_CATCHUP + \
dt.get("default_logo")
return Listitem().from_dict(**{
"label": dt.get("label") or plugin._title,
"art": art or None,
"callback": dt.get("pUrl"),
"properties": {
"IsPlayable": True,
"inputstream": is_helper.inputstream_addon,
"inputstream.adaptive.stream_headers": dt.get("hdrs"),
"inputstream.adaptive.manifest_type": dt.get("proto", "mpd"),
"inputstream.adaptive.license_type": dt.get("drm"),
"inputstream.adaptive.license_key": licenseUrl,
}
})


# Play live stream/ catchup according to params.
# Also insures that user is logged in.
@Resolver.register
@isLoggedIn
def play(plugin, channel_id, showtime=None, srno=None):
def play(plugin, channel_id, showtime=None, srno=None , programId=None, begin=None, end=None):
is_helper = inputstreamhelper.Helper("mpd", drm="com.widevine.alpha")
hasIs = is_helper.check_inputstream()
if not hasIs:
return
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),
Expand All @@ -285,29 +254,42 @@ def play(plugin, channel_id, showtime=None, srno=None):
rjson["showtime"] = showtime
rjson["srno"] = srno
rjson["stream_type"] = "Catchup"
rjson["programId"] = programId
rjson["begin"] = begin
rjson["end"] = end

getUrlHeaders = {
"devicetype":"phone",
"host":"tv.media.jio.com",
"os":"android",
"versioncode":"290",
"Content-Type":"application/json"
}

resp = urlquick.post(GET_CHANNEL_URL, json=rjson).json()
headers = getHeaders()
headers['channelid'] = str(channel_id)
headers['srno'] = rjson["srno"] if "srno" in rjson else str(None)
resp = urlquick.post(GET_CHANNEL_URL, json=rjson, headers=getUrlHeaders, max_age=-1).json()
art = {}
channelName_m3u8 = resp.get("result", "").split("?")[0].split('/')[-1]
channelName = channelName_m3u8[:-5].replace("_"," ")
art["thumb"] = art["icon"] = IMG_CATCHUP + \
resp.get("result", "").split("/")[-1].replace(".m3u8", ".png")
params = getTokenParams()
uriToUse = resp.get("result","") + "?" + urlencode(params)
variant_m3u8 = m3u8.load(resp.get("result","") + "?" + urlencode(params), headers=getHeaders())
if variant_m3u8.is_variant:
quality = len(variant_m3u8.playlists) - 1
uriToUse = uriToUse.replace(resp.get("result", "").split("/")[-1], variant_m3u8.playlists[quality].uri)

cookie = resp.get("result", "").split("?")[1]
headers['cookie'] = cookie
uriToUse = resp.get("result","")

return Listitem().from_dict(**{
"label": plugin._title,
"label": channelName,
"art": art,
# "callback": resp.get("result", "") + "?" + urlencode(params),
"callback": uriToUse,
"properties": {
"IsPlayable": True,
"inputstream": "inputstream.adaptive",
"inputstream.adaptive.stream_headers": "User-Agent=KAIOS",
"inputstream.adaptive.manifest_headers": urlencode(headers),
"inputstream.adaptive.manifest_params": cookie,
"inputstream.adaptive.manifest_type": "hls",
"inputstream.adaptive.license_key": urlencode(params) + "|" + urlencode(getHeaders()) + "|R{SSM}|",
"inputstream.adaptive.license_key": "|" + urlencode(headers) + "|R{SSM}|",
}
})

Expand Down
20 changes: 11 additions & 9 deletions resources/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,23 @@ def login(username, password, mode="unpw"):
if resp.get("ssoToken", "") != "":
_CREDS = {
"ssotoken": resp.get("ssoToken"),
"userId": resp.get("sessionAttributes", {}).get("user", {}).get("uid"),
"uniqueId": resp.get("sessionAttributes", {}).get("user", {}).get("unique"),
"userid": resp.get("sessionAttributes", {}).get("user", {}).get("uid"),
"uniqueid": resp.get("sessionAttributes", {}).get("user", {}).get("unique"),
"crmid": resp.get("sessionAttributes", {}).get("user", {}).get("subscriberId"),
"subcriberid": resp.get("sessionAttributes",{}).get("user", {}).get("subscriberId")
}
headers = {
"User-Agent": "JioTV",
"os": "Android",
"appkey": "NzNiMDhlYzQyNjJm",
"accesstoken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImF1dGhUb2tlbklkIjoiYmQwMmFlMzUtZjc3NS00NjBhLTk4OTYtYjUzY2E3ZmNmMDI3IiwidXNlcklkIjoiODcxMmY2NzgtNzE4MS00MTIxLWEyZmUtMTRmMmUzNTRlZTNmIiwidXNlclR5cGUiOiJKSU8iLCJvcyI6ImFuZHJvaWQiLCJkZXZpY2VUeXBlIjoicGhvbmUiLCJhY2Nlc3NMZXZlbCI6IjkiLCJkZXZpY2VJZCI6IjcwYTZhM2ExMTc2ZGMxMGQiLCJleHRyYSI6IntcIm51bWJlclwiOlwiOFNMQ0J5Q1h2NEFjb0cyMG85MUtiQm03aWRYOGtJSmlRa1FiS3B6dFJ0WU9jbFRtSXc3Uk9hUT1cIixcInBsYW5kZXRhaWxzXCI6e1wiUGFja2FnZUluZm9cIjpbe1wicGxhbmlkXCI6XCIxXCIsXCJzdWJzY3JpcHRpb25zdGFydFwiOjE2NTkwMjI0NDcsXCJzdWJzY3JpcHRpb25lbmRcIjoxNjkwNTU4NDQ3LFwicGxhbnR5cGVcIjpcInByZW1pdW1cIixcImJ1c2luZXNzVHlwZVwiOlwiamlvXCIsXCJpc2FjdGl2ZVwiOnRydWUsXCJub3Rlc1wiOlwiXCJ9XX19Iiwic3Vic2NyaWJlcklkIjoiMTE0MzAzNTMyMSJ9LCJleHAiOjE2NzUwMjI1NTksImlhdCI6MTY3NTAxNTM1OX0.uja0tHTRGSzsEssNEq08JOJyL-Q8C3la9wZQGlapH7DWxvnXq6nzKWGnyRiCMEjcp1V0WSbICSOA_aeN0dxR8w",
"os": "android",
"deviceId": str(uuid4()),
"versionCode": "226",
"devicetype": "phone",
"srno": "200206173037",
"appkey": "NzNiMDhlYzQyNjJm",
"channelid": "100",
"lbcookie": "1",
"os":"android",
"osversion":"11",
"user-agent": "plaYtv/7.0.8 (Linux;Android 11) ExoPlayerLib/2.11.7",
"usergroup": "tvYR7NSNn7rymo3F",
"lbcookie": "1"
"versionCode": "290"
}
headers.update(_CREDS)
with PersistentDict("headers") as db:
Expand Down
2 changes: 1 addition & 1 deletion resources/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
<setting id="Assamese" type="bool" label="Assamese" default="true"/>
<setting id="Urdu" type="bool" label="Urdu" default="true"/>
<setting id="Nepali" type="bool" label="Nepali" default="true"/>
<setting id="Manipuri" type="bool" label="Manipuri" default="true"/>
</category>
<category label="More">
<setting id="cleanup" type="action" label="Clear Cache" action="RunPlugin(plugin://plugin.video.jiotv/resources/lib/main/cleanup/)" option="close"/>
<setting id="popup" type="bool" label="Disable Welcome Popup" default="false"/>
<setting id="extra" type="bool" label="Extra HD Channels" default="false"/>
</category>
</settings>

1 comment on commit ac896c8

@masternkv
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key Error 19 is coming now

Please sign in to comment.