Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """
- A simple little script for getting at the m3u8 for ufc.tv videos
- For free and ethical stream viewing free from proprietary players
- I have this saved as ufctv in a bin dir on my $PATH, so I can call it from wherever
- To login, run: ufctv login
- That will begin an interactive login prompt
- The login details themselves aren't saved, just the cookies for the session
- And the active session is reset any time you login with the "Keep Me Signed In" box anywhere else
- To get a video's m3u8 (can be piped into mpv or others): ufctv uri $UFCTV-URL
- So for example if I want to go back and watch Belfort vs Hendo 3
- % ufctv uri http://www.ufc.tv/video/belfort-vs-henderson-3
- From there you an do what you wish with the m3u8!
- You may wish to pipe the result direct to mpv (which lets you seek around and switch between qualities)
- % ufctv uri http://www.ufc.tv/video/belfort-vs-henderson-3 | xargs mpv
- or
- % ufctv watch http://www.ufc.tv/video/belfort-vs-henderson-3
- Or start ripping with streamlink
- % ufctv uri http://www.ufc.tv/video/belfort-vs-henderson-3 | xargs -I M3U8 streamlink hlsvariant://M3U8 best -o belf-vs-hend.ts
- or
- % ufctv rip http://www.ufc.tv/video/belfort-vs-henderson-3
- You can also rip the stream with ffmpeg, though I've found streamlink does it a bit cleaner
- Right now having trouble with direct to static quality URIs
- Seems Akamai or whoever wants the client to load the playlist first at minimum
- So for ffmpeg ripping it's a bit of hassle as ffmpeg will try to eat every stream in the playlist from what I see
- Streamlink doesn't have that issue
- If you're having trouble with 403 forbiddens still
- Try jumping around between fake devices
- Find user_agents in the script, maybe add some more recent ones, and set it as the fake device
- """
- import argparse
- import getpass
- import json
- import os
- import pickle
- import re
- import subprocess
- import sys
- import logging
- import urllib
- from requests import session
- ufctv_session_path = os.path.expanduser("~/.ufctv")
- proxy_settings = {}
- def main():
- logging.basicConfig(level=logging.INFO)
- parser = argparse.ArgumentParser(description=
- """
- This is a command line tool to help enjoy quality UFC Fight Pass
- content in an ethical manner that respects your freedoms
- """)
- parser.add_argument(
- '-p', '--proxy',
- help="Try to use a proxy to get around geoblock"
- )
- parser.add_argument('operation', choices=[
- 'login',
- 'uri',
- 'watch',
- 'rip'])
- args, rest = parser.parse_known_args()
- if args.proxy:
- proxy_settings['http'] = args.proxy
- proxy_settings['https'] = args.proxy
- if args.operation == 'login':
- return ufctv_login()
- parser.add_argument('video_url')
- parser.add_argument('--byid', action='store_true')
- cams = ['main', 'espanol', 'blue', 'red', 'fence', 'overhead', 'all']
- parser.add_argument(
- '-c', '--cam',
- choices=cams,
- default='main',
- help="Requests a different camera -- only works for PPVs!"
- )
- parser.add_argument(
- '-q', '--quality',
- default='best',
- help='Change quality level (e.g. 3000,4500)'
- )
- parser.add_argument(
- '-sq', '--staticquality',
- default='',
- help='Specifically (URI-level) set quality level (e.g. 3000,4500)'
- )
- parser.add_argument(
- '--tstart',
- default=''
- )
- parser.add_argument(
- '--tend',
- default=''
- )
- args, rest = parser.parse_known_args()
- with ufctv_session() as c:
- if args.cam == 'all':
- streams = get_all_cams(c, args.video_url)
- if not streams:
- logging.warning("No streams found...")
- return 2
- for stream in streams:
- print(stream)
- else:
- stream = None
- if args.byid:
- logging.info("Retrieving m3u8 by using id")
- stream = get_m3u8_by_id(c, args.video_url, cams.index(args.cam), args.staticquality)
- else:
- logging.info("Retrieving m3u8 by scanning page for id")
- stream = get_single_cam(c, args.video_url, cams.index(args.cam), args.staticquality)
- if stream is None:
- logging.warning("No stream was found...")
- return 2
- print(stream)
- if args.operation == 'rip':
- parser.add_argument(
- '--program',
- default='streamlink',
- help='Choose program to use'
- )
- parser.add_argument(
- '--threads',
- default='1',
- help='Change amount of ripping threads'
- )
- args, rest = parser.parse_known_args()
- i = 0
- save_path = "{}-{}.ts".format(args.video_url.split('/')[-1], i)
- while os.path.exists(save_path):
- i += 1
- save_path = "{}-{}.ts".format(args.video_url.split('/')[-1], i)
- sq_used = False
- if args.staticquality:
- sq_used = True
- rip(
- stream,
- save_path,
- quality=args.quality,
- program=args.program,
- static_quality_used=sq_used,
- start=args.tstart,
- end=args.tend
- )
- if args.operation == 'watch':
- watch(stream, quality=args.quality)
- return 0
- user_agents = {
- 'iphone':
- "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
- " AppleWebKit/528.18 (KHTML, like Gecko)"
- " Version/4.0 Mobile/7A341 Safari/528.16"
- ,
- 'ipad':
- "Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us)"
- " AppleWebKit/531.21.10 (KHTML, like Gecko)"
- " Version/4.0.4 Mobile/7B334b Safari/531.21.10"
- ,
- 'chromecast':
- "Mozilla/5.0 (CrKey armv7l 1.4.15250)"
- " AppleWebKit/537.36 (KHTML, like Gecko)"
- " Chrome/31.0.1650.0 Safari/537.36"
- ,
- 'firefox':
- "Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0"
- }
- fake_device = 'chromecast' #'iphone' #'chromecast'
- app_user_agent = user_agents[fake_device]
- def watch(uri, program='streamlink', quality='best'):
- if program == 'streamlink':
- cmd = [
- 'streamlink',
- "hlsvariant://{}".format(uri),
- 'best',
- '--http-header', 'User-Agent={}'.format(app_user_agent),
- '--hls-segment-threads', '2',
- '--player', 'mpv'#,
- #'-cache', '8192'
- ]
- if program == 'mpv':
- cmd = [
- 'mpv',
- uri,
- '--keep-open',
- ]
- print(" ".join(cmd))
- return subprocess.call(cmd)
- def rip(uri, path, quality='best', program='ffmpeg', static_quality_used=False, start=None, end=None):
- cmd = []
- if program == 'streamlink':
- proto = "hlsvariant"
- if static_quality_used:
- proto = "hls"
- cmd = [
- 'streamlink',
- "{}://{}".format(proto, uri),
- quality,
- '-o', path,
- '--http-header', 'User-Agent={}'.format(app_user_agent),
- '--hls-segment-threads', '1',
- #'--hls-live-edge', '5',
- #'--hls-segment-timeout', '120',
- #'--hls-segment-attempts', '20',
- #'--stream-segment-attempts', '20',
- #'--stream-segment-timeout', '120',
- #'--stream-timeout', '120',
- '--retry-open', '5',
- ]
- if program == 'ffmpeg':
- cmd = [
- 'ffmpeg',
- '-report',
- '-loglevel', '48',
- '-rw_timeout', '10000000',
- '-timeout', '10000000',
- '-multiple_requests', '1',
- '-headers', 'User-Agent: {}'.format(app_user_agent)
- ]
- if start:
- cmd.extend(['-ss', start])
- cmd.extend([
- '-i', uri,
- ])
- if end:
- cmd.extend(['-to', end])
- cmd.extend([
- '-c:a', 'copy', '-c:v', 'copy', path
- ])
- print(" ".join(cmd))
- return subprocess.call(cmd)
- def get_single_cam(session, uri, cam, static_qual = ""):
- vid_id = get_video_id(session, uri)
- if vid_id:
- return get_m3u8_by_id(session, vid_id, cam, static_qual)
- def get_all_cams(session, uri, static_qual = ""):
- vid_id = get_video_id(session, uri)
- streams = []
- for cam in range(0, 6):
- stream = get_m3u8_by_id(session, vid_id, cam, static_qual)
- if stream is None: break
- streams.append(stream)
- return streams
- def get_video_id(session, uri):
- r = session.get(uri)
- if not logged_in(r.text):
- logging.warning("Goof Alert: You are not logged in to UFC.TV")
- if video_geo_blocked(r.text):
- logging.warning("Looks like you're geo-blocked, kid")
- vid_id = find_video_id(r.text)
- if vid_id is None:
- logging.warning("Failed to find video ID in page, likely a bug in function find_video_id")
- return None
- logging.info("Video ID found: {}".format(vid_id))
- return vid_id
- def find_video_id(page_html):
- m = re.search('rel="image_src" href=".*?([0-9]+?)_.*?"', page_html)
- if m: return m.group(1)
- def get_m3u8_by_id(session, vid_id, cam, static_qual = ""):
- puburi = "https://www.ufc.tv/service/publishpoint"
- request = {
- 'format': 'json',
- 'type': 'video',
- 'id': vid_id,
- 'cam': cam,
- }
- """
- if 'https' in proxy_settings:
- logging.info("Using HTTPS proxy")
- r = session.post(puburi, data=request, proxies=proxy_settings)
- elif 'http' in proxy_settings:
- logging.info("Using HTTP proxy")
- r = session.post(puburi, data=request, proxies=proxy_settings)
- else:
- """
- r = session.post(puburi, data=request)
- #r = session.post(puburi, data=request, proxies=proxy_settings)
- if r.text:
- stream_info = json.loads(r.text)
- if 'path' not in stream_info:
- logging.warning("No stream m3u8 found, sorry.")
- logging.warning(r.text)
- return None
- else:
- logging.warning("No response from endpoint")
- return None
- if static_qual:
- return stream_info['path'].replace("hd_", "hd_" + static_qual + "_")
- elif fake_device == 'iphone':
- return stream_info['path'].replace("_iphone", "")
- else:
- return stream_info['path']
- def save_cookies(session):
- with open(ufctv_session_path, 'wb') as f:
- pickle.dump(session.cookies, f)
- def load_cookies(session):
- if not os.path.isfile(ufctv_session_path):
- return
- with open(ufctv_session_path, 'rb') as f:
- session.cookies.update(pickle.load(f))
- def video_geo_blocked(html):
- return '<div class="blackout-content">' in html
- def video_allowed(page_html):
- return '<div class="noAccess">' not in page_html
- def logged_in(page_html):
- return "var isLoggedIn = true;" in page_html
- def ufctv_login():
- if os.path.isfile(ufctv_session_path):
- os.remove(ufctv_session_path)
- with ufctv_session() as c:
- login(c)
- save_cookies(c)
- def login(sesh):
- username = input("Please enter your ufc.tv username: ")
- password = getpass.getpass("Please enter your ufc.tv password: ")
- longchoice = input("Tick the 'Keep Me Signed In' box for a long lasting session? [y/n] ")
- longsesh = 'true' if longchoice is 'y' else 'false'
- login = {
- 'username': username,
- 'password': password,
- 'cookielink': longsesh
- }
- r = sesh.post("https://www.ufc.tv/secure/authenticate", data=login)
- if 'loginsuccess' not in r.text:
- print("Login failure -- full response:\n{}\n".format(r.text), file=sys.stderr)
- return False
- return True
- def ufctv_session():
- with session() as c:
- load_cookies(c)
- if fake_device:
- c.headers.update({'User-Agent': app_user_agent})
- # let ufc.tv "feel the proxy"
- if 'https' in proxy_settings:
- logging.info("Testing HTTPS proxy...")
- c.get("https://www.ufc.tv/", proxies=proxy_settings)
- return c
- if __name__ == "__main__":
- sys.exit(main())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement