123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #!/usr/bin/env python3
-
- # itv.py
- # Copyright (C) 2015 Jashandeep Sohi <jashandeep.s.sohi@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- import argparse
- from lxml import etree
- import requests
- import re
- from sys import stderr
- from os import path
- import subprocess
-
- LIVESTREAMER = "localhost:88"
-
- if __name__ == "__main__":
- arg_parser = argparse.ArgumentParser(
- description = "ITV downloader",
- )
- arg_parser.add_argument(
- "url",
- help = "programme url",
- action = "store",
- )
- arg_parser.add_argument(
- "filename",
- help = "output filename",
- action = "store",
- nargs = "?",
- )
- arg_parser.add_argument(
- "-d", "--dir",
- help = "download directory (default: '%(default)s')",
- action = "store",
- default = ".",
- )
- arg_parser.add_argument(
- "-s", "--start",
- help = "start at given time (default: '%(default)s')",
- action = "store",
- default = 0,
- type = int,
- )
- arg_parser.add_argument(
- "-e", "--end",
- help = "end at given time (default: '%(default)s')",
- action = "store",
- default = -1,
- type = int,
- )
- arg_parser.add_argument(
- "-p", "--proxy",
- help = "proxy address (e.g. 'http://2.13.1.2:1234', "
- "'socks://3.1.2.3:1234', etc)",
- action = "store",
- default = ""
- )
- resume_group = arg_parser.add_mutually_exclusive_group()
- resume_group.add_argument(
- "-r", "--resume",
- help = "attempt to resume (set by default)",
- action = "store_true",
- default = True
- )
- resume_group.add_argument(
- "-R", "--no-resume",
- help = "don't attempt to resume (overwrites old file)",
- action = "store_false",
- dest = "resume"
- )
- args = arg_parser.parse_args()
-
- session = requests.Session()
- session.headers.update({
- "User-Agent": "Mozilla/5.0 (Windows NT 5.1; rv:32.0) Gecko/20100101 "
- "Firefox/32.0",
- })
-
- page_req = session.get(args.url)
- pid_match = re.search('data-video-id="(.*?)"', page_req.text)
-
- try:
- pid = pid_match.group(1).replace("\\", "")
- except:
- arg_parser.error("could not parse video pid from page")
-
- soap_msg1 = """
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:itv="http://schemas.datacontract.org/2004/07/Itv.BB.Mercury.Common.Types" xmlns:com="http://schemas.itv.com/2009/05/Common">
- <soapenv:Header/>
- <soapenv:Body>
- <tem:GetPlaylist>
- <tem:request>
- <itv:ProductionId>{pid}</itv:ProductionId>
- <itv:RequestGuid>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</itv:RequestGuid>
- <itv:Vodcrid>
- <com:Id/>
- <com:Partition>itv.com</com:Partition>
- </itv:Vodcrid>
- </tem:request>
- <tem:userInfo>
- <itv:Broadcaster>Itv</itv:Broadcaster>
- <itv:GeoLocationToken>
- <itv:Token/>
- </itv:GeoLocationToken>
- <itv:RevenueScienceValue>ITVPLAYER.12.18.4</itv:RevenueScienceValue>
- <itv:SessionId/>
- <itv:SsoToken/>
- <itv:UserToken/>
- </tem:userInfo>
- <tem:siteInfo>
- <itv:AdvertisingRestriction>None</itv:AdvertisingRestriction>
- <itv:AdvertisingSite>ITV</itv:AdvertisingSite>
- <itv:AdvertisingType>Any</itv:AdvertisingType>
- <itv:Area>ITVPLAYER.VIDEO</itv:Area>
- <itv:Category/>
- <itv:Platform>DotCom</itv:Platform>
- <itv:Site>ItvCom</itv:Site>
- </tem:siteInfo>
- <tem:deviceInfo>
- <itv:ScreenSize>Big</itv:ScreenSize>
- </tem:deviceInfo>
- <tem:playerInfo>
- <itv:Version>2</itv:Version>
- </tem:playerInfo>
- </tem:GetPlaylist>
- </soapenv:Body>
- </soapenv:Envelope>
- """
- soap_msg2="""
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:itv="http://schemas.datacontract.org/2004/07/Itv.BB.Mercury.Common.Types" xmlns:com="http://schemas.itv.com/2009/05/Common">
- <soapenv:Header/>
- <soapenv:Body>
- <tem:GetPlaylist>
- <tem:request>
- <itv:ProductionId/>
- <itv:RequestGuid>A26C4B97-C300-F83A-C5A6-2C0FD584D9B8</itv:RequestGuid>
- <itv:Vodcrid>
- <com:Id>{pid}</com:Id>
- <com:Partition>itv.com</com:Partition>
- </itv:Vodcrid>
- </tem:request>
- <tem:userInfo>
- <itv:Broadcaster>Itv</itv:Broadcaster>
- <itv:DM>584e4d9a-fa89-4398-9033-f6ed4dead584</itv:DM>
- <itv:RevenueScienceValue>ITVPLAYER.2.18.10.+build.21057aabd9</itv:RevenueScienceValue>
- <itv:SessionId/>
- <itv:SsoToken/>
- <itv:UserToken/>
- </tem:userInfo>
- <tem:siteInfo>
- <itv:AdvertisingRestriction>None</itv:AdvertisingRestriction>
- <itv:AdvertisingSite>ITV</itv:AdvertisingSite>
- <itv:AdvertisingType>Any</itv:AdvertisingType>
- <itv:Area>ITVPLAYER.VIDEO</itv:Area>
- <itv:Category/>
- <itv:Platform>DotCom</itv:Platform>
- <itv:Site>ItvCom</itv:Site>
- </tem:siteInfo>
- <tem:deviceInfo>
- <itv:ScreenSize>Big</itv:ScreenSize>
- </tem:deviceInfo>
- <tem:playerInfo>
- <itv:Version>2</itv:Version>
- </tem:playerInfo>
- </tem:GetPlaylist>
- </soapenv:Body>
- </soapenv:Envelope>
- """
- if re.search("sim\d",pid):
- soap_msg = soap_msg2.format(pid = pid)
- is_live = True
- else:
- soap_msg = soap_msg1.format(pid = pid)
- is_live = False
-
- media_req = session.post(
- "http://mercury.itv.com/PlaylistService.svc",
- headers = {
- "Referer": "http://www.itv.com/mercury/Mercury_VideoPlayer.swf?v=1.6.479/[[DYNAMIC]]/2",
- "Content-type": "text/xml; charset=utf-8",
- "SOAPAction": "http://tempuri.org/PlaylistService/GetPlaylist"
- },
- data = soap_msg,
- proxies = {"http": args.proxy} if args.proxy else None,
- timeout = 20
- )
- media_req_tree = etree.fromstring(media_req.text)
- #print media_req.text
- title = media_req_tree.xpath("//ProgrammeTitle/text()")[0] if media_req_tree.xpath("//ProgrammeTitle/text()") else "title"
- ep_title = media_req_tree.xpath("//EpisodeTitle/text()")[0] if media_req_tree.xpath("//EpisodeTitle/text()") else "episode"
-
- media_files = media_req_tree.xpath("//VideoEntries/Video/MediaFiles")[0]
-
- rtmp_url = media_files.xpath("@base")[0]
- media_file = media_files.xpath(
- "MediaFile[not(../MediaFile/@bitrate > @bitrate)]"
- )[0]
- bitrate = int(media_file.xpath("@bitrate")[0]) // 1000
- rtmp_playpath = media_file.xpath("URL/text()")[0]
-
- file_path = path.join(
- args.dir,
- args.filename if args.filename else re.sub(
- "[\W_]+",
- "-",
- "-".join(map(str, filter(None, (
- title,
- ep_title,
- bitrate,
- args.start,
- args.end if args.end > 0 else None
- ))))
- ).lower() + ".flv"
- )
-
- print "http://%s/%s"%(LIVESTREAMER,rtmp_url),
- print "playpath="+rtmp_playpath,
- print "pageUrl="+args.url,
- if is_live: print "live",
- print "swfVfy="+"http://www.itv.com/mercury/Mercury_VideoPlayer.swf"
-
- cmd = [
- "rtmpdump",
- "-r", rtmp_url,
- "--playpath", rtmp_playpath,
- "--pageUrl", args.url,
- "--swfVfy", "http://www.itv.com/mercury/Mercury_VideoPlayer.swf"
- "?v=1.6.479/[[DYNAMIC]]/2"
- "--flashVer", "WIN 15,0,0,189",
- "--flv", file_path,
- "--resume" if args.resume else "",
- "--start={}".format(args.start),
- "--stop={}".format(args.end) if args.end > 0 else ""
- ]
-
- url2 = "http://%s/%s playpath=%s pageUrl=%s swfVfy=http://www.itv.com/mercury/Mercury_VideoPlayer.swf%s"%(LIVESTREAMER,rtmp_url,rtmp_playpath,args.url," live" if is_live else "")
- cmd2 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url2]
- if is_live:
- cmd.append("--live")
- #print cmd2
-
- print url2
- print '\nrtmpdump -r "%s" --playpath "%s" --pageUrl "%s" --swfVfy "http://www.itv.com/mercury/Mercury_VideoPlayer.swf"%s -o output.flv\n'%(rtmp_url,rtmp_playpath,args.url," live" if is_live else "")
- proc = subprocess.Popen(cmd2)
- try:
- proc.communicate()
-
- except KeyboardInterrupt:
- pass
-
- # vim: tabstop=2 expandtab
|