Here is a pick-and-mix, a series, or part-series downloader for UKTVPlay.co.uk.
Most programmes are 1080p and their catalogue is growing. UKTVPlay.co.uk is the online presence for Dave, Yesterday, Drama and W. All of their output is encrypted.
The script appended downloads using address bar url(s) of the form
h t t p s://uktvplay.co.uk/shows/the-bill/series-29/episode-1/6315559703112 the 13 digit number must be in the url to be valid.
It uses either a remote CDM or your local CDM. The local CDM may be configured to use either WKS-KEYS or Pywidevine. If using the Pywidevine option, do not run in the WKS-KEYS folder..
A series option is available by starting the program script by including an argument, S, as:-
The pick-and-mix option discards the argument s (or S).Code:python uktvplay.py s
A verbose setting can be made True or False withe the script setting section near the head of the code.
If VERBOSE = True all episodes from all series of the same title will be shown on the screen.
No support whatsoever!Code:# angela 30:08_2023 # UKTVPlay.co.uk ''' pip install requirements.txt copied from below into file called requirements.txt and run command above httpx==0.24.1 pyfiglet==0.8.post1 pyperclip==1.8.2 pywidevine==1.6.0 Requests==2.31.0 termcolor==2.3.0 # Google search 'installing python modules' if you need help. # also needed will be N_m3u8DL-RE and it's dependencies; ffmpeg, mkvmerge # see https://forum.videohelp.com/threads/408557-Decryption-The-Last-Crusade for details # Either use in WKS-KEYS folder with local CDM or use pywidewine anywhere other than WKS-KEYS # Series Option: # For series download start program with 'python uktvplay.py S' (use S or s) # Respond to on-screen prompts either PASTE or key entry here # Choose series to download by series number entry or enter 'all' for all-series # Single series download needs episode begin and end mumber # Or enter 'all' for all episodes in a series. # Select partial series download by selecting begin and end range. # For one episode begin=end (but why not use Pick & Mix?) # For Pick & Mix Option start the script with 'python uktvplay.py' # select any number of video-page urls and have them in clipboard # Launch this script with and follow screen instructions to use CLIPBOARD. # Running a system with both WKS-KEYS and pywidevine installed is possible. # WKS-KEYS uses an older protobuf version 3.20.3 installed by pip # if you 'pip install pywidevine' after that, pywidevinve installs protobuf version 4.x.x # WKS-KEYS will complain that the protobufs need re-compiling when you run WKS-KEYS after that. # See here for instruction how to re-compile WKS-KEYS protobufs. # https://forum.videohelp.com/threads/409040-Correcting-Protobuf-Downgrade-to-3-19-0-error#post2684955 # if your WKS-KEYS does not have a .proto file PM me. # Once WKS-KEYS has upgraded protobufs.. # you can use python's pywidevine module and a wvd file instead of WKS-KEYS but both will run on the system. # To create a wvd file (use full paths): # pywidevine create-device -k "path/to/device_private_key" -c "path/to/device_client_id_blob" -t "ANDROID" -l 3 -o "output_path" # then enter your wvd output_path below. # Do not run this script in the WKS-KEYS folder otherwise system pywidevine will not be found. # ensure all urls look similar to this # https://uktvplay.co.uk/shows/mrs-mandela/series-1/episode-1/6277180923001 # and NOT this # https://uktvplay.co.uk/shows/mrs-mandela/watch-online ########################## Change the settings to your requirements below. ########################## ''' import requests import json import re import httpx import subprocess from pathlib import Path import pyperclip as PC import pyfiglet as PF from termcolor import colored from base64 import b64encode ####### SETTINGS ######### OUT_PATH = Path('output') OUT_PATH.mkdir(exist_ok=True, parents=True) # ! do not edit WVD_PATH = "/home/angela/android_sdk.wvd" # Example only! change this if using pywidevine PYWIDEVINE = False # use pywidevine or WKS-KEYS VERBOSE = True # set this True to list all episodes across all Series of the same title or False ###### END SETTINGS ######## pk = "BCpkADawqM3vt2DxMZ94FyjAfheKk_-e92F-hnuKgoJMh2hgaASJJV_gUeYm710md2yS24_4PfOEbF_SSTNM4PijWNnwZG8Tlg4Y40XyFQh_T9Vq2460u3GXCUoSQOYlpfhbzmQ8lEwUmmte" SERIES = False global ALLLIST ALLLIST = False global ALLSERIES ALLSERIES = False class Videodata: count = int(0) def __init__(self): self.episodes = [] self.videoid = '' self.vidslug = '' self.total = 0 self.sernum = '' Videodata.count += 1 def getbyname(self): return self.__class__.__name__ def add_episodes(self,sernum, epnum, vidslug, videoid ): self.episodes.append([sernum, epnum, vidslug, videoid]) def get_episodes(self): return self.episodes def set_total(self, total): self.total = total def get_total(self): return self.total def get_sernum(self): return self.series def set_sernum(self, num): self.series = num def getcount(self): return (Videodata.count) # use wvd def get_keys(pssh ,lic_url): print("Using pywidevine WVD on this machine") from pywidevine.cdm import Cdm from pywidevine.device import Device from pywidevine.pssh import PSSH pssh = PSSH(pssh) device = Device.load(WVD_PATH) cdm = Cdm.from_device(device) session_id = cdm.open() challenge = cdm.get_license_challenge(session_id, pssh) licence = httpx.post(lic_url, data=challenge, headers=None) cdm.parse_license(session_id, licence.content) mykeys = '' for key in cdm.get_keys(session_id): if key.type=='SIGNING': pass else: print(f"Keys found {key.kid.hex}:{key.key.hex()}") mykeys += f"{key.kid.hex}:{key.key.hex()}" cdm.close(session_id) return mykeys # use wks-keys def get_wkskeys(pssh, lic_url): print("Using WKS-KEYS and CDM on this machine") from pywidevine.L3.cdm import deviceconfig from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=None, device=deviceconfig.device_android_generic) widevine_license = httpx.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=None) license_b64 = b64encode(widevine_license.content) wvdecrypt.update_license(license_b64) Correct, keyswvdecrypt = wvdecrypt.start_process() if Correct: mykeys = '' for key in keyswvdecrypt: mykeys += key +' ' print(f"Keys found {mykeys}\n") return mykeys def get_pssh(mpd_url): mpd = requests.get(mpd_url).text lines = mpd.split("\n") for line in lines: m = re.search('<cenc:pssh>(AAAA.+?)</cenc:pssh>', line) if m: pssh = m.group(1) return pssh def pad_number(match): number = int(match.group(1)) return format(number, "02d") def get_series(start_url, start): global ALLSERIES global ALLLIST mykeepstring = '' mystringurls = '' series_data = {} # dict: {0: [sernum, Videodata instance], etc...} parts = start_url.split('/') brdslg = parts[4] response = requests.get(f"https://vschedules.uktv.co.uk/vod/brand/?slug={brdslg}") if response.status_code == 200: myjson = json.loads(response.content) else: print (f"Response gave an error {response.status_code} \n {response.content}") exit(0) series_ids = [] series = (myjson['series']) series_len = len(series) for i in range(0 , series_len): series_ids.append(series[i]['id']) index = 0 for id in series_ids: response = requests.get(f"https://vschedules.uktv.co.uk/vod/series/?id={id}") if response.status_code == 200: myjson = json.loads(response.content) else: print("Error fetching series data\nResponse gave an error {response.status_code} \n {response.content}") exit(0) sernum = int(myjson["number"]) series_data[index] = Videodata() series_data[index].set_sernum(sernum) total_episodes = int(myjson['total_episodes']) series_data[index].set_total(total_episodes) if VERBOSE: print (f"Series {sernum}") for i in range(0 , total_episodes): # total for series epsdata = myjson['episodes'] vidid = epsdata[i]['watch_online_link'].split('/')[6] epnum = epsdata[i]['episode_number'] series_data[index].add_episodes(sernum, epnum ,brdslg, vidid ) if VERBOSE: print (f"https://uktvplay.co.uk/shows/{brdslg}/series-{sernum}/episode-{epnum}/{vidid}") index += 1 myseriesdata = [] for i in range (0 , Videodata.count): if ALLSERIES: interim = series_data[i].get_episodes() myseriesdata.append(interim) elif series_data[i].get_sernum() == start: myreturndata = series_data[i] if not ALLSERIES: print(f"Series {myreturndata.get_sernum()} has {myreturndata.get_total()} episodes") r1 = input("Enter the first episode number required or 'all'. ") if r1 == 'all' or r1 == 'All': ALLLIST = True else: r1 = int(r1) r2 = int(input("Enter the last episode in the range required. ")) if ALLLIST: r1 = 1 r2 = int(myreturndata.get_total()) try: if ALLSERIES: for s in range(0, len(myseriesdata)): for r in myseriesdata[s]: mykeepstring = (f"https://uktvplay.co.uk/shows/{r[2]}/series-{r[0]}/episode-{r[1]}/{r[3]}") mystringurls += (mykeepstring + '\n') return mystringurls else: print(f"Series {myreturndata.get_sernum()} has {myreturndata.get_total()} episodes from which you have selected {(r2-r1)+1} ") print('Fetching...') if int(myreturndata.get_total()) < int(r2): print(f"Impossible to select those {(r2-r1)+1} episode numbers when the sequence only goes to {myreturndata.get_total()}") raise ValueError except Exception as e: print(e) print("Confused!!") exit(0) mystringurls = '' for i in range(r1-1,r2 ): data = myreturndata.episodes[i] mykeepstring = (f"https://uktvplay.co.uk/shows/{data[2]}/series-{myreturndata.get_sernum()}/episode-{data[1]}/{data[3]}") if VERBOSE: print(mykeepstring) mystringurls += (mykeepstring + '\n') return mystringurls def main(): if SERIES: print("Series Mode Selected!\n") print("URLS need a 13 digit number at the end,\nfor example,\nhttps://uktvplay.co.uk/shows/bangers-and-cash/series-8/episode-1/6332436895112\n\n") links = [] start_url = input("Enter an episode URL from any Series with the same Title. ") start = input("Enter the Series number from which you want episodes. Or 'all' ") global ALLSERIES if 'all' in start: ALLSERIES = True start = int(999) else: start = int(start) try: glom = get_series(start_url, start) links = glom.split('\n') except Exception as e: #print(e) print(f"Error: Need a valid digit for the Series. Check Series {start} exists") exit(0) else: input("Have page URL(s) in clipboard. Enter when ready!") links = PC.paste().split('\n') for link in links: if link == '': break try: videoid = (link.split('?')[0]).split('/')[7] videonamesplit = link.split('/',7) videoname = videonamesplit[4]+videonamesplit[5]+videonamesplit[6] videoname = videoname.replace('series-','_S').replace('episode-', 'E') videoname = re.sub(r"(\d+)", pad_number, videoname).title() headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1788.0', 'Accept': f'application/json;pk={pk}', 'Accept-Language': 'en-GB,en;q=0.5', 'Origin': 'https://uktvplay.co.uk', } response = requests.get( f'https://edge.api.brightcove.com/playback/v1/accounts/1242911124001/videos/{videoid}', headers=headers, ).text myjson = json.loads(response) mpd = myjson["sources"][2]["src"] license = myjson["sources"][2]["key_systems"]["com.widevine.alpha"]["license_url"] pssh = get_pssh(mpd) except: # DannyBoi message print("ERROR: Ensure your URL ends with a 13 digit number\nand if in series-mode, you actully PASTED (ctrl+v)\nthe link. Then try again") break if PYWIDEVINE: mykeys = get_keys(pssh ,license) else: mykeys = get_wkskeys(pssh, license) # system name for N_m3u8DL-RE binary. It needs to be in your system's PATH m3u8dl = 'N_m3u8DL-RE' command = [ m3u8dl, mpd, "--auto-select", '--check-segments-count=False', "-sv", "best", "-sa", "id='audio-0'", "-ss", "id='subtitles-0':for=all", "--save-name", videoname, "--save-dir", "./output", "--tmp-dir", "./", "-mt", "--key", mykeys, "-M", "format=mkv:muxer=mkvmerge", '--no-log', ] subprocess.run(command) exit(0) if __name__ == "__main__": from sys import argv if argv and len(argv) > 1: if argv[1]=='S' or argv[1]=='s': SERIES = True title = PF.figlet_format(' UKTVPlay ', font='smslant') print(colored(title, 'green')) main() exit(0)
+ Reply to Thread
Results 1 to 30 of 55
-
Last edited by A_n_g_e_l_a; 30th Aug 2023 at 07:50. Reason: Update 30/08/2023
-
just grabs the keys nothing else, can u update it to grab the mpds aswell as download and decrypt the vid/audio plz
-
For the avoidance of doubt:-
[Attachment 73229 - Click to enlarge]
[Attachment 73230 - Click to enlarge] -
Don't paste acres of garbage - what is the point?
N_m3u8DL-CLI 3.0.1.0 IS NOT THE SAME as N_m3u8DL-RE
https://github.com/nilaoda/N_m3u8DL-RE/releases -
its working nw but why did u not pack and upload all of the files instead of just the script?
Last edited by Dannyboi; 17th Aug 2023 at 12:04.
-
-
help
[Attachment 73236 - Click to enlarge]
EDIT: i fix it just need a UK VPNLast edited by justnerd; 17th Aug 2023 at 16:35.
-
Note, uktv play is quite an unreliable source for 1080 quality, as their bitrate settings must be some strange vbr, and you get some really wild bitrate fluctuations per episode (some are nice 4.8k+, while others are 2k-1k)
-
Could I please ask some questions regarding this part of the code?
[CODE# if you have a CDM and have not yet installed python pywidevine module.
# do so with 'pip install pywidevine'.
# Create a file ending wvd with which to locate your CDM
# pywidevine create-device -k "path/to/device_private_key" -c "path/to/device_client_id_blob" -t "ANDROID" -l 3 -o "output_path"
# and provide your output path below - currently this is an example path
WVD_PATH = "/home/angela/android_sdk.wvd"
][/CODE]
First off I have my own CDM and in the WS-KEYS folder there is a folder called pywidevine. Yes I understand not to run UKTVPlay.py in the WS_KEYS folder, but is the script still using the pywidevine or does a new one need to be installed elsewhere by running pip install pywidevine?
Secondly I'm confused by "pywidevine create-device -k "path/to/device_private_key" -c "path/to/device_client_id_blob" -t "ANDROID" -l 3 -o "output_path" Is this some code to create the path and then it's added to the WVD_PATH = ? Or do I just navigate through the folders of pywidevine and copy the path into that part of the code.
Any help would be appreciated -
It is explained in te pre-amble, but YES.
What is confusing? It is a command you run to create a file with a wvd extension. In my case I called it android_sdk.wvd
That is off the wall? Where did that come from?
It is some code to create a FILE with a wvd suffix which is added to the script at WVD_PATH=
Why not just set I_HAVE_MY_OWN_CDM = False?Last edited by A_n_g_e_l_a; 18th Aug 2023 at 02:32.
-
-
Yes similar! I was thinking the one in the Unnatural History Museum, on the second floor, next to Spells, Incantations, Charms and Potions. I give thee 'Ye Olde Clipboard' https://support.microsoft.com/en-us/windows/clipboard-in-windows-c436501e-985d-1c8d-97...a-fe46ddf338c6 guard it well prithee!
-
Last edited by Dannyboi; 18th Aug 2023 at 07:14.
-
Exactly as Angela said. Once it's on clipboard, just PRESS THE ENTER KEY. That's the big upside-down-L shaped key below the big Backspace key and above the big right hand Shift.
Don't do any pasting or right clicking of the mouse. -
-
-
Single episodes downloading perfectly but Series gives below error
C:\ffmpeg\bin\wks-keys>python uktvplay.py S
←[32m __ ____ _________ _____ __
/ / / / //_/_ __/ | / / _ \/ /__ ___ __
/ /_/ / ,< / / | |/ / ___/ / _ `/ // /
\____/_/|_| /_/ |___/_/ /_/\_,_/\_, /
/___/
←[0m
Paste the start video URL for the Series. start
Enter the number of episodes. 7
Traceback (most recent call last):
File "C:\ffmpeg\bin\wks-keys\uktvplay.py", line 260, in <module>
main()
File "C:\ffmpeg\bin\wks-keys\uktvplay.py", line 196, in main
videoid = (link.split('?')[0]).split('/')[7]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range -
The script is just complaining of Operator Error - you trying to take the place of DannyBoi? You've not fed enough information in.
Code:Rubbish in = Rubbish out
Code:# ensure all urls look similar to this # https://uktvplay.co.uk/shows/mrs-mandela/series-1/episode-1/6277180923001 # and NOT this # https://uktvplay.co.uk/shows/mrs-mandela/watch-online
-
Of course that was my first thought. I must have made an input error. So I read and reread the instructions and tried with numerous series same error.
an example of a series I tried https://uktvplay.co.uk/shows/state-of-play/series-1/episode-1/6314867208112 This series has 6 episodes. Same error.
This is a genuine request, so please do not cast aspersions on me simply because others are unwilling to learn.
Thanks -
Works for me Ringy9
[Attachment 73306 - Click to enlarge]
[Attachment 73307 - Click to enlarge]
[Attachment 73308 - Click to enlarge]
[Attachment 73309 - Click to enlarge]
[Attachment 73310 - Click to enlarge]
[Attachment 73311 - Click to enlarge]
Using the url you provided. What else am I to think?
And the last comment at post 1. "No support. When I post stuff it works for me."
You did Paste (as asked) (ctrl +V) rather than expecting the clipboard copy to be read?Last edited by A_n_g_e_l_a; 21st Aug 2023 at 05:25.
-
Code:
You did Paste (as asked) (ctrl +V) rather than expecting the clipboard copy to be read?
-
@A_n_g_e_l_a
I'm sorry that you had to remove your script but just to let you know that i found it extremely useful. Thank you very much. -
Rather naively I thought I wanted to democratize decryption for the masses. So I posted code that had three ways of getting keys; Pywidvine, WKS-KEYS, or a remote service. The remote service gave anyone, who dropped in from Google, the ability to be able to download from ITVX or UKTVPlay, without much fuss.
Only, I now realise, those Googlers hadn't spent any time downloading, getting keys and decrypting by hand, so didn't have the tools, nor any experience running scripts.
But they arrive, wave after wave, with huge expectations via a search engine.
Having had time to relfect, I have removed the remote service option and re-posted the script. Users will need a CDM so (hopefully) will have done the preparatory work and have a suitable system on which to run code.
Similar Threads
-
question how to download video files from site uktvplay.co.uk
By barry25 in forum Video Streaming DownloadingReplies: 6Last Post: 16th Aug 2023, 07:59 -
More UKTVplay file issues
By sixpence668 in forum Video Streaming DownloadingReplies: 10Last Post: 14th Apr 2022, 15:23 -
Help downloading from UKTVPlay
By JustTheWayItIs in forum Video Streaming DownloadingReplies: 8Last Post: 18th Feb 2022, 15:51 -
how to stream uktvplay.uktv.co.uk video files and remove the drm
By elm in forum Video Streaming DownloadingReplies: 5Last Post: 31st Dec 2018, 05:42