VideoHelp Forum



Support our site by donate $5 directly to us Thanks!!!

Try StreamFab Downloader and download streaming video from Netflix, Amazon!



+ Reply to Thread
Page 1 of 2
1 2 LastLast
Results 1 to 30 of 31
  1. delete
    Last edited by swappyison; 22nd Oct 2023 at 00:37.
    Quote Quote  
  2. i don't know what the certificate for base 64 is
    Quote Quote  
  3. Search, Learn, Download! Karoolus's Avatar
    Join Date
    Oct 2022
    Location
    Belgium
    Search Comp PM
    Originally Posted by swappyison View Post
    i don't know what the certificate for base 64 is
    it's None


    Code:
    import base64
    import requests
    import pyperclip
    from pywidevine.L3.cdm import cdm, deviceconfig
    from base64 import b64encode
    from pywidevine.L3.getPSSH import get_pssh
    from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt
    
    def generate_pssh(kid: str):
        str1 = '000000387073736800000000edef8ba979d64acea3c827dcd51d21ed000000181210'
        str3 = '48e3dc959b06'
        return base64.b64encode(bytes.fromhex(str1 + kid + str3)).decode()
    
    def get_keys(pssh, lic_url,certificate_b64=None):
        wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=certificate_b64, device=deviceconfig.device_android_generic)
        widevine_license = requests.get(url=lic_url, headers=headers)
        
        license_b64 = b64encode(widevine_license.content)
        wvdecrypt.update_license(license_b64)
        Correct, keyswvdecrypt = wvdecrypt.start_process()
        
        if Correct:
            return keyswvdecrypt
        else:
            return None
    
    pssh = input('PSSH: ')
    lic_url = input('License URL: ')
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.1234.56 Safari/537.36',
        'Referer': 'https://www.jiocinema.com/',
    }
    
    keys = get_keys(pssh, lic_url)
    
    if keys:
        print()
        for key in keys:
            print('--key ' + key)
    
        key_string = ' '.join([f"--key {key}" for key in keys])
        pyperclip.copy(key_string)
    else:
        print("\nFailed to retrieve keys from JioCinema API.")


    Also
    Code:
    widevine_license = requests.get(url=lic_url, headers=headers)
    afaik a license request is always a POST and not GET so I think it should be
    Code:
    widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=headers)
    Last edited by Karoolus; 7th Aug 2023 at 03:51.
    Quote Quote  
  4. thanks it works, btw in the headers i found out there are just two things 'x-playbackid' and 'unique id'. that seem to change for every video. How can i incorporate it in the code so i don't have to change it manually in the code before executing?
    thanks
    Quote Quote  
  5. Search, Learn, Download! Karoolus's Avatar
    Join Date
    Oct 2022
    Location
    Belgium
    Search Comp PM
    Originally Posted by swappyison View Post
    thanks it works, btw in the headers i found out there are just two things 'x-playbackid' and 'unique id'. that seem to change for every video. How can i incorporate it in the code so i don't have to change it manually in the code before executing?
    thanks
    I don't see them in the headers in your script you posted above.

    Post the script you have right now, so I'm not breaking anything else by making a change to your script
    Quote Quote  
  6. Code:
    import base64
    import requests
    import pyperclip
    from pywidevine.L3.cdm import cdm, deviceconfig
    from base64 import b64encode
    from pywidevine.L3.getPSSH import get_pssh
    from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt
    import subprocess
    
    def generate_pssh(kid: str):
        str1 = '000000387073736800000000edef8ba979d64acea3c827dcd51d21ed000000181210'
        str3 = '48e3dc959b06'
        return base64.b64encode(bytes.fromhex(str1 + kid + str3)).decode()
    
    def get_keys(pssh, lic_url, certificate_b64=None):
        wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=certificate_b64, device=deviceconfig.device_android_generic)
        widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=headers)
        
        license_b64 = b64encode(widevine_license.content)
        wvdecrypt.update_license(license_b64)
        Correct, keyswvdecrypt = wvdecrypt.start_process()
        
        if Correct:
            return keyswvdecrypt
        else:
            return None
    
    pssh = input('PSSH: ')
    lic_url = input('License URL: ')
    mpd_url = input('MPD URL: ')
    
    headers = {
        # Headers remain the same
        # ...
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0',
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.5',
        # 'Accept-Encoding': 'gzip, deflate, br',
        'Referer': 'https://www.jiocinema.com/',
        'accesstoken': 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJJZCI6ImFjNGU1Y2E5LWY4YTYtNGU0Mi1iYjkxLWFiNjQzY2QxMTMxZSIsInVzZXJUeXBlIjoiR1VFU1QiLCJhcHBOYW1lIjoiUkpJTF9KaW9DaW5lbWEiLCJkZXZpY2VJZCI6IjI1MTcwMTM4MjUiLCJkZXZpY2VUeXBlIjoicGhvbmUiLCJvcyI6ImlvcyIsInByb2ZpbGVJZCI6IjBiMThjYWE3LTFmMWQtNDEwZi04NWJjLWIyNWJiNzg2Y2Q0MCIsImFkSWQiOiIyNTE3MDEzODI1In0sImV4cCI6MTY5MTQxNjg5OCwiaWF0IjoxNjkxNDA5Njk4fQ.MQFzyzkwhooJI617fpP7o-6zNkih9a9qlEE7f2kmgDzCqAcBfjiKCNb1GtGg3K_Cb3ROSg42czOYOeJIs4NUbQ',
        'appname': 'RJIL_JioCinema',
        'content-type': 'application/octet-stream',
        'deviceid': '2517013825',
        'devicetype': 'Web',
        'isdownload': 'false',
        'os': 'android',
        'uniqueid': 'ac4e5ca9-f8a6-4e42-bb91-ab643cd1131e',
        'versioncode': '560',
        'x-feature-code': 'ytvjywxwkn',
        'x-platform': 'Web',
        'x-playbackid': 'c13ba3aa-2c14-4d99-ba6f-2fd7d627dfcd',
        'Origin': 'https://www.jiocinema.com',
        'Connection': 'keep-alive',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'cross-site',
        # Requests doesn't support trailers
        # 'TE': 'trailers',
    }
    
    keys = get_keys(pssh, lic_url)
    
    if keys:
        print("\nKeys generated:")
        for key in keys:
            print('--key ' + key)
    
        # Convert keys to a comma-separated string
        keys_str = ':'.join(keys)
    
        # Construct the command with the MPD URL
        command = f"./N_m3u8DL-RE -M format=mp4 --key {keys_str} \"{mpd_url}\" --save-name ge.mp4"
    
        # Execute the command using subprocess
        try:
            subprocess.run(command, shell=True, check=True)
        except subprocess.CalledProcessError as e:
            print(f"Error occurred: {e}")
    else:
        print("\nFailed to retrieve keys from JioCinema API.")
    Quote Quote  
  7. Search, Learn, Download! Karoolus's Avatar
    Join Date
    Oct 2022
    Location
    Belgium
    Search Comp PM
    Code:
    import base64
    import requests
    import pyperclip
    from pywidevine.L3.cdm import cdm, deviceconfig
    from base64 import b64encode
    from pywidevine.L3.getPSSH import get_pssh
    from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt
    import subprocess
    
    def generate_pssh(kid: str):
        str1 = '000000387073736800000000edef8ba979d64acea3c827dcd51d21ed000000181210'
        str3 = '48e3dc959b06'
        return base64.b64encode(bytes.fromhex(str1 + kid + str3)).decode()
    
    def get_keys(pssh, lic_url, certificate_b64=None):
        wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=certificate_b64, device=deviceconfig.device_android_generic)
        widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=headers)
        
        license_b64 = b64encode(widevine_license.content)
        wvdecrypt.update_license(license_b64)
        Correct, keyswvdecrypt = wvdecrypt.start_process()
        
        if Correct:
            return keyswvdecrypt
        else:
            return None
    
    pssh = input('PSSH: ')
    lic_url = input('License URL: ')
    mpd_url = input('MPD URL: ')
    x-playbackid = input('X-playbackid: ')
    uniqueid = input('UniqueID: ')
    
    headers = {
        # Headers remain the same
        # ...
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0',
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.5',
        # 'Accept-Encoding': 'gzip, deflate, br',
        'Referer': 'https://www.jiocinema.com/',
        'accesstoken': 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJJZCI6ImFjNGU1Y2E5LWY4YTYtNGU0Mi1iYjkxLWFiNjQzY2QxMTMxZSIsInVzZXJUeXBlIjoiR1VFU1QiLCJhcHBOYW1lIjoiUkpJTF9KaW9DaW5lbWEiLCJkZXZpY2VJZCI6IjI1MTcwMTM4MjUiLCJkZXZpY2VUeXBlIjoicGhvbmUiLCJvcyI6ImlvcyIsInByb2ZpbGVJZCI6IjBiMThjYWE3LTFmMWQtNDEwZi04NWJjLWIyNWJiNzg2Y2Q0MCIsImFkSWQiOiIyNTE3MDEzODI1In0sImV4cCI6MTY5MTQxNjg5OCwiaWF0IjoxNjkxNDA5Njk4fQ.MQFzyzkwhooJI617fpP7o-6zNkih9a9qlEE7f2kmgDzCqAcBfjiKCNb1GtGg3K_Cb3ROSg42czOYOeJIs4NUbQ',
        'appname': 'RJIL_JioCinema',
        'content-type': 'application/octet-stream',
        'deviceid': '2517013825',
        'devicetype': 'Web',
        'isdownload': 'false',
        'os': 'android',
        'uniqueid': uniqueid,
        'versioncode': '560',
        'x-feature-code': 'ytvjywxwkn',
        'x-platform': 'Web',
        'x-playbackid': x-playbackid,
        'Origin': 'https://www.jiocinema.com',
        'Connection': 'keep-alive',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'cross-site',
        # Requests doesn't support trailers
        # 'TE': 'trailers',
    }
    
    keys = get_keys(pssh, lic_url)
    
    if keys:
        print("\nKeys generated:")
        for key in keys:
            print('--key ' + key)
    
        # Convert keys to a comma-separated string
        keys_str = ':'.join(keys)
    
        # Construct the command with the MPD URL
        command = f"./N_m3u8DL-RE -M format=mp4 --key {keys_str} \"{mpd_url}\" --save-name ge.mp4"
    
        # Execute the command using subprocess
        try:
            subprocess.run(command, shell=True, check=True)
        except subprocess.CalledProcessError as e:
            print(f"Error occurred: {e}")
    else:
        print("\nFailed to retrieve keys from JioCinema API.")
    Quote Quote  
  8. thank you, I was wondering instead of entering PSSH, can I extract PSSH from mpd url?
    thanks
    Quote Quote  
  9. 'x_playbackid = input('X-playbackid: ')'
    Quote Quote  
  10. x-playbackid = input('X-playbackid: ')
    ^^^^^^^^^^^^
    SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?
    Quote Quote  

  11. @swappyison
    I was wondering instead of entering PSSH, can I extract PSSH from mpd url?


    accesstoken is needed and this module:
    Code:
    pip install pyjwt
    with accesstoken working for a few hours
    since all important data comes from jwt, it might work for those who have a premium account..
    (don't have it so that just guess..)

    Image
    [Attachment 72989 - Click to enlarge]


    Code:
    from pathlib import Path
    import subprocess
    import jwt
    import re
    
    access_token = '< accesstoken here >'
    
    print('\ntest link: https://www.jiocinema.com/movies/sergeant-bhojpuri/3767689\ntest link: https://www.jiocinema.com/tv-shows/kaalkoot/1/janam-din/3788001\n')
    
    link = input('link: ')
    link_id = re.findall(r'.*/(.*)', link)[0].strip()
    
    m3u8DL_RE = 'N_m3u8DL-RE.exe'
    
    def replace_invalid_chars(title: str) -> str:
        invalid_chars = {'<': '\u02c2', '>': '\u02c3',
        ':': '\u02d0', '"': '\u02ba', '/': '\u2044',
        '\\': '\u29f9', '|': '\u01c0', '?': '\u0294',
        '*': '\u2217'}
        
        return ''.join(invalid_chars.get(c, c) for c in title)
    
    decoded = jwt.decode(access_token, options={"verify_signature": False})
    #print(f'\n{decoded}\n')
    
    deviceId = decoded['data']['deviceId']
    uniqueid = decoded['data']['userId']
    appName = decoded['data']['appName']
    
    ######
    
    import requests
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    
    headers2 = {
        'authority': 'apis-jiovoot.voot.com',
        'accept': 'application/json, text/plain, */*',
        'accesstoken': access_token,
        'appname': appName,
        'content-type': 'application/json',
        'deviceid': deviceId,
        'origin': 'https://www.jiocinema.com',
        'referer': 'https://www.jiocinema.com/',
        'uniqueid': uniqueid,
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
        'versioncode': '560',
        'x-platform': 'androidweb',
        'x-platform-token': 'web',
    }
    
    json_data2 = {
        '4k': False,
        'ageGroup': '18+',
        'appVersion': '3.4.0',
        'bitrateProfile': 'xhdpi',
        'capability': {
            'drmCapability': {
                'aesSupport': 'yes',
                'fairPlayDrmSupport': 'yes',
                'playreadyDrmSupport': 'none',
                'widevineDRMSupport': 'yes',
            },
            'frameRateCapability': [
                {
                    'frameRateSupport': '30fps',
                    'videoQuality': '1440p',
                },
            ],
        },
        'continueWatchingRequired': True,
        'dolby': False,
        'downloadRequest': False,
        'hevc': False,
        'kidsSafe': False,
        'manufacturer': 'Windows',
        'model': 'Windows',
        'multiAudioRequired': True,
        'osVersion': '10',
        'parentalPinValid': True,
    }
    
    response2 = requests.post('https://apis-jiovoot.voot.com/playbackjv/v4/'+link_id+'', headers=headers2, json=json_data2, verify=False).json()
    
    contentType = response2['data']['contentType']
    
    if contentType == 'MOVIE':
        movie_name = response2['data']['name']
        title = f'{movie_name}'
    
    elif contentType == 'EPISODE':
        showName = response2['data']['show']['name']
        season_num = int(response2['data']['episode']['season'])
        episode_num = int(response2['data']['episode']['episodeNo'])
        episode_title = response2['data']['fullTitle']
        
        title = f'{showName} - S{season_num:02d}E{episode_num:02d} - {episode_title}'
    
    else:
        movie_name = response2['data']['name']
        title = f'{movie_name}'
    
    title = replace_invalid_chars(title)
    print(f'\n{title}\n')
    
    mpd = response2['data']['playbackUrls'][0]['url']
    
    lic_url = response2['data']['playbackUrls'][0]['licenseurl']
    
    try:
        import requests
        
        headers03 = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
        }
        
        response03 = requests.get(mpd, headers=headers03, verify=False).text
        
        pssh = re.findall(r'<cenc:pssh>(.{20,170})</cenc:pssh>', response03)[0].strip()
        print(f'{pssh}\n')
    
        import base64, requests, sys, xmltodict, json
        from pywidevine.L3.cdm import cdm, deviceconfig
        from base64 import b64encode
        from pywidevine.L3.getPSSH import get_pssh
        from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt
        import time
        import re  
        
        headers = {
            'authority': 'prod.media.jio.com',
            'accesstoken': access_token,
            'appname': appName,
            'content-type': 'application/octet-stream',
            'deviceid': deviceId,
            'devicetype': 'Web',
            'isdownload': 'false',
            'origin': 'https://www.jiocinema.com',
            'os': 'android',
            'referer': 'https://www.jiocinema.com/',
            'uniqueid': uniqueid,
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
            'versioncode': '570',
            'x-feature-code': 'ytvjywxwkn',
            'x-platform': 'Web',
            'x-playbackid': uniqueid,
        }
        
        def WV_Function(pssh, lic_url, cert_b64=None):
            wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=cert_b64, device=deviceconfig.device_android_generic)                   
            widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=headers, verify=False)
            license_b64 = b64encode(widevine_license.content)
            wvdecrypt.update_license(license_b64)
            Correct, keyswvdecrypt = wvdecrypt.start_process()
            if Correct:
                return Correct, keyswvdecrypt
        Correct, keys = WV_Function(pssh, lic_url)
        
        for key in keys:
            print('--key ' + key)
        
        ke_ys = ' '.join([f'--key {key}' for key in keys]).split()
        
        print()
        subprocess.run([m3u8DL_RE,
                        '-M', 'format=mkv:muxer=ffmpeg',
                        '--concurrent-download',
                        '--log-level', 'INFO',
                        '--save-name', 'video', mpd, *ke_ys])
    
    except IndexError: #DRM free
        print()
        subprocess.run([m3u8DL_RE,
                        '-M', 'format=mkv:muxer=ffmpeg',
                        '--concurrent-download',
                        '--log-level', 'INFO',
                        '--save-name', 'video', mpd])
    
    try:
        Path('video.mkv').rename(''+title+'.mkv')
        print(f'{title}.mkv \nall done!\n')
    except FileNotFoundError:
        print("[ERROR] no mkv file")
    Last edited by sk8ordi3; 24th Aug 2023 at 11:58. Reason: script updated.. (handle both lic url type)
    Quote Quote  
  12. delete
    Last edited by swappyison; 22nd Oct 2023 at 00:36.
    Quote Quote  
  13. delete
    Last edited by swappyison; 22nd Oct 2023 at 00:38.
    Quote Quote  
  14. Originally Posted by swappyison View Post
    hi i am trying to use a similar code for a website that has no playbackid, has an api like this https://gwapi.zee5.com/content/tvshow/0-6-199?translation=en&country=IN , and response headers that include nl and sdrm. like this url: https://www.zee5.com/tv-shows/details/bhabi-ji-ghar-par-hai/0-6-199/maryada-threatens-.../0-1-6z5403446
    could you please help?
    this content is not drm protected:
    https://www.zee5.com/tv-shows/details/bhabi-ji-ghar-par-hai/0-6-199/maryada-threatens-.../0-1-6z5403446

    show you an url is drm protected and free..
    Quote Quote  
  15. than use hls and not widevine
    (if you fast maybe you can still play in vlc)

    Code:
    https://zee5vodnd.akamaized.net/hls1/elemental/hls/TV_SHOWS/AND_TV/August2023/04082023/Episode/BQC_CS_Bhabi_Ji_Ghar_Par_Hai_Ep2129_Episode_04082023_hi_fdf0e55f58421769bf5d67a1e2418a30/index-phone.m3u8?hdnea=st=1691481560~exp=1691485280~acl=/hls1/elemental/hls/TV_SHOWS/AND_TV/August2023/04082023/Episode/BQC_CS_Bhabi_Ji_Ghar_Par_Hai_Ep2129_Episode_04082023_hi_fdf0e55f58421769bf5d67a1e2418a30/index-phone.m3u8*~hmac=d5b521e9024dfc3611930401e2ac17002a98f5ca03712697970194ca4fe39194
    Quote Quote  
  16. thanks
    Last edited by swappyison; 8th Aug 2023 at 03:44.
    Quote Quote  
  17. Member
    Join Date
    Jul 2023
    Location
    India
    Search Comp PM
    Originally Posted by sk8ordi3 View Post

    @swappyison
    I was wondering instead of entering PSSH, can I extract PSSH from mpd url?


    accesstoken is needed and this module:
    Code:
    pip install pyjwt
    with accesstoken working for a few hours
    since all important data comes from jwt, it might work for those who have a premium account..
    (don't have it so that just guess..)

    Image
    [Attachment 72989 - Click to enlarge]


    Code:
    from pathlib import Path
    import subprocess
    import jwt
    import re
    
    access_token = '< accesstoken here >'
    
    print('\ntest link: https://www.jiocinema.com/movies/sergeant-bhojpuri/3767689\ntest link: https://www.jiocinema.com/tv-shows/kaalkoot/1/janam-din/3788001\n')
    
    link = input('link: ')
    link_id = re.findall(r'.*/(.*)', link)[0].strip()
    
    m3u8DL_RE = 'N_m3u8DL-RE.exe'
    
    def replace_invalid_chars(title: str) -> str:
        invalid_chars = {'<': '\u02c2', '>': '\u02c3',
        ':': '\u02d0', '"': '\u02ba', '/': '\u2044',
        '\\': '\u29f9', '|': '\u01c0', '?': '\u0294',
        '*': '\u2217'}
        
        return ''.join(invalid_chars.get(c, c) for c in title)
    
    decoded = jwt.decode(access_token, options={"verify_signature": False})
    #print(f'\n{decoded}\n')
    
    deviceId = decoded['data']['deviceId']
    uniqueid = decoded['data']['userId']
    appName = decoded['data']['appName']
    
    ######
    
    import requests
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    
    headers2 = {
        'authority': 'apis-jiovoot.voot.com',
        'accept': 'application/json, text/plain, */*',
        'accesstoken': access_token,
        'appname': appName,
        'content-type': 'application/json',
        'deviceid': deviceId,
        'origin': 'https://www.jiocinema.com',
        'referer': 'https://www.jiocinema.com/',
        'uniqueid': uniqueid,
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
        'versioncode': '560',
        'x-platform': 'androidweb',
        'x-platform-token': 'web',
    }
    
    json_data2 = {
        '4k': False,
        'ageGroup': '18+',
        'appVersion': '3.4.0',
        'bitrateProfile': 'xhdpi',
        'capability': {
            'drmCapability': {
                'aesSupport': 'yes',
                'fairPlayDrmSupport': 'yes',
                'playreadyDrmSupport': 'none',
                'widevineDRMSupport': 'yes',
            },
            'frameRateCapability': [
                {
                    'frameRateSupport': '30fps',
                    'videoQuality': '1440p',
                },
            ],
        },
        'continueWatchingRequired': True,
        'dolby': False,
        'downloadRequest': False,
        'hevc': False,
        'kidsSafe': False,
        'manufacturer': 'Windows',
        'model': 'Windows',
        'multiAudioRequired': True,
        'osVersion': '10',
        'parentalPinValid': True,
    }
    
    response2 = requests.post('https://apis-jiovoot.voot.com/playbackjv/v4/'+link_id+'', headers=headers2, json=json_data2, verify=False).json()
    #print(f'\n{response2}\n')
    
    contentType = response2['data']['contentType']
    
    if contentType == 'MOVIE':
        movie_name = response2['data']['name']
        title = f'{movie_name}'
    
    elif contentType == 'EPISODE':
        showName = response2['data']['show']['name']
        season_num = int(response2['data']['episode']['season'])
        episode_num = int(response2['data']['episode']['episodeNo'])
        episode_title = response2['data']['fullTitle']
        
        title = f'{showName} - S{season_num:02d}E{episode_num:02d} - {episode_title}'
    
    else:
        movie_name = response2['data']['name']
        title = f'{movie_name}'
    
    title = replace_invalid_chars(title)
    print(f'\n{title}\n')
    
    mpd = response2['data']['playbackUrls'][0]['url']
    #print(f'\n{mpd}\n')
    
    lic_url = response2['data']['playbackUrls'][0]['licenseurl']
    #print(f'\n{lic_url}\n')
    
    try:
        import requests
        
        headers03 = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
        }
        
        response03 = requests.get(mpd, headers=headers03, verify=False).text
        
        pssh = re.findall(r'<cenc:pssh>(.{20,170})</cenc:pssh>', response03)[0].strip()
        print(f'{pssh}\n')
    
        import base64, requests, sys, xmltodict, json
        from pywidevine.L3.cdm import cdm, deviceconfig
        from base64 import b64encode
        from pywidevine.L3.getPSSH import get_pssh
        from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt
        import time
        import re
        
        headers = {
            'authority': 'key-jiocinema.voot.com',
            'accesstoken': access_token,
            'appname': appName,
            'content-type': 'application/octet-stream',
            'deviceid': deviceId,
            'devicetype': 'Web',
            'isdownload': 'false',
            'origin': 'https://www.jiocinema.com',
            'os': 'android',
            'referer': 'https://www.jiocinema.com/',
            'uniqueid': uniqueid,
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',
            'versioncode': '560',
            'x-platform': 'Web',
            'x-playbackid': uniqueid,
        }
        
        def WV_Function(pssh, lic_url, cert_b64=None):
            wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=cert_b64, device=deviceconfig.device_android_generic)                   
            widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=headers, verify=False)
            license_b64 = b64encode(widevine_license.content)
            wvdecrypt.update_license(license_b64)
            Correct, keyswvdecrypt = wvdecrypt.start_process()
            if Correct:
                return Correct, keyswvdecrypt
        Correct, keys = WV_Function(pssh, lic_url)
        
        for key in keys:
            print('--key ' + key)
        
        ke_ys = ' '.join([f'--key {key}' for key in keys]).split()
        
        print()
        subprocess.run([m3u8DL_RE,
                        '-M', 'format=mkv:muxer=ffmpeg',
                        '--concurrent-download',
                        '--log-level', 'INFO',
                        '--save-name', 'video', mpd, *ke_ys])
    
    except IndexError: #DRM free
        print()
        subprocess.run([m3u8DL_RE,
                        '-M', 'format=mkv:muxer=ffmpeg',
                        '--concurrent-download',
                        '--log-level', 'INFO',
                        '--save-name', 'video', mpd])
    
    try:
        Path('video.mkv').rename(''+title+'.mkv')
        print(f'{title}.mkv \nall done!\n')
    except FileNotFoundError:
        print("[ERROR] no mkv file")
    what to enter in access token ???
    Quote Quote  
  18. Member
    Join Date
    Oct 2022
    Location
    Behind You
    Search PM
    Originally Posted by sarvo99 View Post
    what to enter in access token ???
    The access token.
    I help all that ask.
    Quote Quote  
  19. Search, Learn, Download! Karoolus's Avatar
    Join Date
    Oct 2022
    Location
    Belgium
    Search Comp PM
    Originally Posted by Magicians View Post
    Originally Posted by sarvo99 View Post
    what to enter in access token ???
    The access token.
    Image
    [Attachment 73128 - Click to enlarge]


    Genius!
    Quote Quote  
  20. Member
    Join Date
    Jul 2023
    Location
    India
    Search Comp PM
    Originally Posted by Magicians View Post
    Originally Posted by sarvo99 View Post
    what to enter in access token ???
    The access token.
    thanks bro i meant where to find it but no problem i found out myself. btw u r a genius
    Quote Quote  
  21. @sk8ordi3, bro jiocinema has basically two different license urls for DRM videos:

    1.) starting from key-jiocinema, like this: https://key-jiocinema.voot.com/keydelivery/v2/widevine?lt=exp=1692868783~st=1692867883...f0b1e893726fe7
    2) starting from prod.media-proxy, like this:https://prod.media.jio.com/proxy?video_id=2000536858
    currently script is working for the second license url type only
    Quote Quote  
  22. show both types plain video url, because putting two license url's in there is useless...

    so this is the proxy one:
    https://www.jiocinema.com/tv-shows/mangala-gowri-maduve/1/rajeev-searches-for-his-baby/3537388

    what is the other video url?
    Quote Quote  
  23. no i meant some videos have license url of one kind (like key-jiocinema) and others have of other kind(like proxy one).
    Quote Quote  
  24. Originally Posted by swappyison View Post
    no i meant some videos have license url of one kind (like key-jiocinema) and others have of other kind(like proxy one).
    I do not understand..
    show me the video url that doesn't work with the script...
    Quote Quote  
  25. got it
    script updated
    (now handle both lic url type)
    Quote Quote  
  26. @sk8ordi3
    access_token = '< accesstoken here >'
    Is there a way to automate updating access token instead of manual input?
    Quote Quote  
  27. Member lottery's Avatar
    Join Date
    Jan 2019
    Location
    United States
    Search Comp PM
    how to get new accesstoken from jiocinema
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!