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
Results 1 to 13 of 13
  1. Debbie akduyurye's Avatar
    Join Date
    Jun 2023
    Location
    Knightsbridge, UK
    Search Comp PM
    Some scripts on this forum are unfortunately very slow, fragile, and unnecessarily complex. This is videohelp.com, not videoconfusion.com. The goal here is to provide the simplest, most efficient, and robust script to download content from itv.com without the need for downloading anything other than the essential components. No browser extensions, no clipboard dependencies, just paste your URLs and go.

    To download content, simply copy URLs from the address bar

    E.g.

    Code:
    python itv.py https://www.itv.com/watch/love-island/2a3697/2a3697a0460

    Setup

    Code:
    sudo pacman -S mkvtoolnix-gui
    yay -S n-m3u8dl-re-bin
    pip install httpx selectolax
    Get mp4decrypt
    https://github.com/axiomatic-systems/Bento4#on-linux-and-other-platforms-using-cmake


    Script

    itv.py

    Code:
    import sys
    import platform
    import subprocess
    from base64 import b64encode
    from concurrent.futures import ThreadPoolExecutor, as_completed
    from pathlib import Path
    
    from httpx import URL, Client
    from selectolax.lexbor import LexborHTMLParser
    
    out = Path('out')
    out.mkdir(exist_ok=True,parents=True)
    
    
    def download(url: str) -> None:
        client = Client(headers={'authority':'www.itv.com','user-agent':'AppleWebKit/537.36'},timeout=20)
        title,data = get_data(client,url)
        video = data['Playlist']['Video']
        media = video['MediaFiles']
        mpd_url = [f'{video["Base"]}{y}' for x in media if (y:=URL(x['Href'])).path.endswith('.mpd')][0]
        lic_url = [x['KeyServiceUrl'] for x in media][0]
        pssh = get_pssh(client,mpd_url)
        key = get_key(client,pssh,lic_url)
        m3u8dl = 'N_m3u8DL-RE' if platform.system() in {'Windows','Darwin'} else 'n-m3u8dl-re'
        subprocess.run([
            m3u8dl,
            mpd_url,
            '--append-url-params',
            '--header','cookie: hdntl=~data=hdntl~hmac=' + '.',  # append any random byte
            '--header','host: itvpnpdotcom.blue.content.itv.com',
            '--header',f'user-agent: {client.headers["user-agent"]}',
            '--auto-select',
            '--save-name',title,
            '--save-dir','./out',
            '--tmp-dir','./',
            '-mt',
            '--key',key,
            '-M',
            'format=mkv:muxer=mkvmerge',
            '--no-log',
        ])
    
    
    def get_data(client: Client, url: str) -> tuple:
        html = LexborHTMLParser(client.get(url).text)
        title = html.css_first('title').text()
        magni_url = html.css_first('[data-video-id]').attributes.get('data-video-id')
        featureset = {k:('mpeg-dash','widevine','outband-webvtt','hd','single-track') for k in ('min','max')}
        payload = {'client':{'id':'browser'},'variantAvailability':{'featureset':featureset,'platformTag':'dotcom'}}
        return title, client.post(magni_url,json=payload).json()
    
    
    def get_key(client:Client, pssh:str, lic_url:str) -> str:
        payload = {'license':lic_url,'headers':'connection: keep-alive','pssh':pssh,'buildInfo':'','proxy':'','cache':True}
        return LexborHTMLParser(client.post('https://cdrm-project.com/wv',json=payload).text).css_first('li').text()
    
    
    def get_pssh(client:Client, mpd_url:str) -> str:
        version = '3870737368'  # b'8pssh'
        system_id = 'EDEF8BA979D64ACEA3C827DCD51D21ED'
        data = '48E3DC959B06'
        key_id = (LexborHTMLParser(client.get(mpd_url).text).css_first('ContentProtection').attributes.get('cenc:default_kid').replace('-',''))
        s = f'000000{version}00000000{system_id}000000181210{key_id}{data}'
        return b64encode(bytes.fromhex(s)).decode()
    
    
    def main():
        urls = sys.argv[1:]
        with ThreadPoolExecutor() as e: [f.result() for f in as_completed(e.submit(download,u) for u in urls)]
    
    
    if __name__ == "__main__":
        main()
    Last edited by akduyurye; 21st Jun 2023 at 09:20. Reason: Handle OSX
    Quote Quote  
  2. Member
    Join Date
    May 2023
    Location
    England
    Search Comp PM
    Much appreciated, thank you! Thanks also for updating it for Mac.

    p.s. if you can post a similarly-easy Channel4 solution that would be brilliant too!
    Last edited by PhilipG; 20th Jun 2023 at 10:17.
    Quote Quote  
  3. Originally Posted by akduyurye View Post
    This is videohelp.com, not videoconfusion.com
    You've used this phrase multiple times with multiple accounts by now. You must be real proud of it. It's a nice one.

    Great script, though! I always like like seeing high-quality work. It's a nice learning opportunity for someone like myself. And this is a bit nicer way of presenting it than doing it while directly insulting other members at the same time like you did on your last account.

    Looking forward to seeing more of your work.
    Quote Quote  
  4. Other scripts are "unnecessarily complex" because they don't outsource the decryption/CDM part to an external 3rd party server. Appreciate the gesture here and all but it's not like this is some innovative new method, you're just doing the "complicated" part remotely. Sure it's more end-user friendly, but essentially you're putting a load on someone else's server and creating a dependency elsewhere.

    This is like saying brewing beer is unnecessarily complex when it can also be found in the store.

    Besides, claiming this uses "no CDM" is just false.
    It does use a CDM, just not a local one.
    Last edited by mike94; 21st Jun 2023 at 02:46.
    I cannot help via Telegram, MSN, ICQ - no unsolicited DMs please.
    All knowledge can be obtained by reading the information on these forums.
    Quote Quote  
  5. Debbie akduyurye's Avatar
    Join Date
    Jun 2023
    Location
    Knightsbridge, UK
    Search Comp PM
    Completely agree dear. Although one could then argue about the terms "external" and "3rd party", as dumping android data with frida scripts and downloading/decrypting content with m3u8 and mp4decrypt is dependent on their current implementations. So there's "no avoiding dependencies" in general, again this can be argued. I understand your point though, and as for the unnecessary complexities, I'm specifically referring to the overuse of browser extensions, clipboard management, regex + magic number indices for data processing, etc.

    There is no mention of innovation here, just "Fast". The only potential innovation here is my use of an arbitrary hmac in the cookie.
    Quote Quote  
  6. Anonymous84
    Guest
    --
    Last edited by Anonymous84; 8th May 2024 at 18:34. Reason: --
    Quote Quote  
  7. This is very useful, I'd been using the 'magni' contents for itv, but getting the 'magni' URL automatically is something I'd not contemplated.

    Interesting to know about that HMAC too.
    Quote Quote  
  8. Debbie akduyurye's Avatar
    Join Date
    Jun 2023
    Location
    Knightsbridge, UK
    Search Comp PM
    Originally Posted by tuskacz View Post
    Originally Posted by akduyurye View Post
    Completely agree dear. Although one could then argue about the terms "external" and "3rd party", as dumping android data with frida scripts and downloading/decrypting content with m3u8 and mp4decrypt is dependent on their current implementations. So there's "no avoiding dependencies" in general, again this can be argued. I understand your point though, and as for the unnecessary complexities, I'm specifically referring to the overuse of browser extensions, clipboard management, regex + magic number indices for data processing, etc.

    There is no mention of innovation here, just "Fast". The only potential innovation here is my use of an arbitrary hmac in the cookie.
    Stop claiming you have monopoly for solving issues in video downloads, you don't. You sound like typical british imperialist who thinks they're the the best and rest of the world is 3rd world. No, dick.
    People do things in different ways, and as long as it leads to same outcome, nobody cares.
    Enjoy your brexit btw.
    For you my dear: https://www.youtube.com/watch?v=sQiI5k8FS7A
    Quote Quote  
  9. I don't know when, but this stopped working

    HTML Code:
    python3 itv.py https://www.itv.com/watch/love-island/2a3697/2a3697a0460
    Traceback (most recent call last):
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 10, in map_exceptions
        yield
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/backends/sync.py", line 28, in read
        return self._sock.recv(max_bytes)
      File "/usr/lib/python3.10/ssl.py", line 1259, in recv
        return self.read(buflen)
      File "/usr/lib/python3.10/ssl.py", line 1132, in read
        return self._sslobj.read(len)
    TimeoutError: The read operation timed out
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 60, in map_httpcore_exceptions
        yield
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 104, in __iter__
        for part in self._httpcore_stream:
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_sync/connection_pool.py", line 338, in __iter__
        for part in self._stream:
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_sync/http11.py", line 315, in __iter__
        raise exc
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_sync/http11.py", line 308, in __iter__
        for chunk in self._connection._receive_response_body(**kwargs):
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_sync/http11.py", line 177, in _receive_response_body
        event = self._receive_event(timeout=timeout)
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_sync/http11.py", line 191, in _receive_event
        data = self._network_stream.read(
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/backends/sync.py", line 26, in read
        with map_exceptions(exc_map):
      File "/usr/lib/python3.10/contextlib.py", line 153, in __exit__
        self.gen.throw(typ, value, traceback)
      File "/home/user/.local/lib/python3.10/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions
        raise to_exc(exc)
    httpcore.ReadTimeout: The read operation timed out
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "/home/user/Documents/har/itv.py", line 73, in <module>
        main()
      File "/home/user/Documents/har/itv.py", line 69, in main
        with ThreadPoolExecutor() as e: [f.result() for f in as_completed(e.submit(download,u) for u in urls)]
      File "/home/user/Documents/har/itv.py", line 69, in <listcomp>
        with ThreadPoolExecutor() as e: [f.result() for f in as_completed(e.submit(download,u) for u in urls)]
      File "/usr/lib/python3.10/concurrent/futures/_base.py", line 451, in result
        return self.__get_result()
      File "/usr/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
        raise self._exception
      File "/usr/lib/python3.10/concurrent/futures/thread.py", line 58, in run
        result = self.fn(*self.args, **self.kwargs)
      File "/home/user/Documents/har/itv.py", line 17, in download
        title,data = get_data(client,url)
      File "/home/user/Documents/har/itv.py", line 45, in get_data
        html = LexborHTMLParser(client.get(url).text)
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_client.py", line 1045, in get
        return self.request(
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_client.py", line 821, in request
        return self.send(request, auth=auth, follow_redirects=follow_redirects)
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_client.py", line 922, in send
        raise exc
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_client.py", line 916, in send
        response.read()
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_models.py", line 805, in read
        self._content = b"".join(self.iter_bytes())
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_models.py", line 823, in iter_bytes
        for raw_bytes in self.iter_raw():
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_models.py", line 881, in iter_raw
        for raw_stream_bytes in self.stream:
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_client.py", line 124, in __iter__
        for chunk in self._stream:
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 103, in __iter__
        with map_httpcore_exceptions():
      File "/usr/lib/python3.10/contextlib.py", line 153, in __exit__
        self.gen.throw(typ, value, traceback)
      File "/home/user/.local/lib/python3.10/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
        raise mapped_exc(message) from exc
    httpx.ReadTimeout: The read operation timed out
    Quote Quote  
  10. Member
    Join Date
    Oct 2022
    Location
    Behind You
    Search PM
    Originally Posted by Sawyer View Post
    I don't know when, but this stopped working
    The site it uses to get keys went down ages ago. You need your own cdm again or you should edit the script with a new site that gives you keys
    I help all that ask.
    Quote Quote  
  11. Already did that, have changed to a new site and have these errors.
    Quote Quote  
  12. Member
    Join Date
    Oct 2022
    Location
    Behind You
    Search PM
    Originally Posted by akduyurye View Post
    Completely agree dear. Although one could then argue about the terms "external" and "3rd party", as dumping android data with frida scripts and downloading/decrypting content with m3u8 and mp4decrypt is dependent on their current implementations. So there's "no avoiding dependencies" in general, again this can be argued. I understand your point though, and as for the unnecessary complexities, I'm specifically referring to the overuse of browser extensions, clipboard management, regex + magic number indices for data processing, etc.

    There is no mention of innovation here, just "Fast". The only potential innovation here is my use of an arbitrary hmac in the cookie.
    This script is now worthless. You did nothing special, just made a ticking timebomb that would stop working.

    If users actually got their own cdm they then don't have to depend on any external 3rd party service that will stop working months down the line.
    I help all that ask.
    Quote Quote  
  13. Member
    Join Date
    Oct 2022
    Location
    Behind You
    Search PM
    Originally Posted by Sawyer View Post
    Already did that, have changed to a new site and have these errors.
    This script wont work anymore. Get your own cdm and use another script.
    I help all that ask.
    Quote Quote  



Similar Threads

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