Skip to content

Instantly share code, notes, and snippets.

Created March 3, 2010 07:44
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save anonymous/320415 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import sys
import re
import io, gzip
import subprocess
import base64, random
try:
import http.client as client
except:
import httplib as client
#####################################################################################
#
# rai.py - version 0.4a
#
#####################################################################################
#
# License GNU GPLv2
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
####################################################################################
#
#
# USAGE python3 rai.py [-vlcdir=<dir>][-uagent=<user-agent>][--ttAuth=<encoded>][-progs=(<xml_filepath>)][(channel|video_on_demand)]
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Notice:
# channel = RaiUno | RaiDue | RaiTre | RaiQuattro
# RaiNews24 | RaiSport+ | RaiStoria | RaiEdu | RaiGulp
# RaiSatExtra | RaiSatPremium | RaiSatCinema | RaiSatYoyo
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Change Log
# + 0.4a
# - Updated ttAuth generation algorithm
# - Improved efficency in "encode" functions
# - Arguments management moved from "mms()" inner code into an explicit "arguments()" function
# - The importable module is refactored from "mms()" to "playerURL()" now
# - Defined an "authCode()" function witch returns ttAuth code
# - Deprecated old "encode" functions
# + 0.4
# - Add tv channel programs list support (XML Format)
# - Can now be imported as module, exposing "mms()"
# - Add ttAuth argument useful for external software integration
# - Bugfix in vlcdir argument: now automatically appends '/' character
# - Refactoring
# + 0.3
# - Add Video-On-demand support
# - Update of key in encode2 function
# - Bugfix in encode2 fucntion: j-index rotation is setted by key length
# - Refactoring
#
# + 0.2
# - Update of ttAuth generation algorithm
#
# + 0.1
# - Creation of ttAuth
vlc_dir = "."
progs_file = "programs.xml"
chan_name = ""
ttAuth = ""
stream = ""
agent = "Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.7) Gecko/20100106 Ubuntu/9.10 (karmic) Firefox/3.6"
isVoD = False
isPrograms = False
urls = {
"RaiUno": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=983",
"RaiDue": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=984",
"RaiTre": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=986",
"RaiQuattro": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=75708",
"RaiNews24": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=1",
"RaiSport+": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=4145",
"RaiStoria": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=24269",
"RaiEdu": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=24268",
"RaiGulp": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=4119",
"RaiSatExtra": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=72382",
"RaiSatPremium": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=72383",
"RaiSatCinema": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=72381",
"RaiSatYoyo": "http://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=72384",
}
def videoURL(pageURL):
re_page = "^http://(?P<host>[a-zA-Z0-9]*\.([a-zA-Z0-9]*\.)+[a-zA-Z0-9]*)(?P<path>/[\w\-\+\~\%\#\.\/\?\=]*)"
match_page = re.match(re_page, pageURL).groupdict()
page_connection = client.HTTPConnection(match_page["host"])
page_connection.putrequest("POST", match_page["path"])
page_connection.putheader("User-Agent", agent)
page_connection.putheader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
page_connection.putheader("Accept-Language", "it-it,it;q=0.8,en-us;q=0.5,en;q=0.3")
page_connection.putheader("Accept-Encoding", "gzip,deflate")
page_connection.putheader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
page_connection.putheader("Keep-Alive", "115")
page_connection.putheader("Connection", "keep-alive")
page_connection.putheader("Cookie", "volume=0,5; ns_cookietest=true; ns_session=true")
page_connection.putheader("Cache-Control", "max-age=0")
page_connection.endheaders()
page_response = page_connection.getresponse().read()
page_connection.close()
page = str(gzip.GzipFile(fileobj=io.BytesIO(page_response)).read(), "utf8")
return re.search("(?P<video>http://mediapolis.rai.it.*)\"", page).groupdict()["video"]
def streamURL(pageURL):
re_url = "^http://(?P<host>[a-zA-Z0-9]*\.([a-zA-Z0-9]*\.)+[a-zA-Z0-9]*)(?P<path>/[\w\-\+\~\%\#\.\/]*)\?cont\=(?P<chanid>\w*)"
match_url = re.match(re_url, pageURL).groupdict()
global ttAuth
if ttAuth == "":
ttAuth = authCode(match_url["chanid"])
asx_connection = client.HTTPConnection(match_url["host"])
asx_connection.putrequest("POST", match_url["path"]+"?cont="+match_url["chanid"])
asx_connection.putheader("User-Agent", agent)
asx_connection.putheader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
asx_connection.putheader("Accept-Language", "it-it,it;q=0.8,en-us;q=0.5,en;q=0.3")
asx_connection.putheader("Accept-Encoding", "gzip,deflate")
asx_connection.putheader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
asx_connection.putheader("Connection", "keep-alive")
asx_connection.putheader("Keep-Alive", "115")
asx_connection.putheader("viaurl", "www.rai.tv")
asx_connection.putheader("ttAuth", ttAuth)
asx_connection.putheader("Content-Length", "0")
asx_connection.endheaders()
asx_response = asx_connection.getresponse().read()
asx_connection.close()
asx = bytes.decode(asx_response)
return re.search("(?P<mms>mms://.*)\"", asx).groupdict()["mms"]
def raiDate():
date_connection = client.HTTPConnection("videowall.rai.it")
date_connection.putrequest("GET", "/cgi-bin/date")
date_connection.putheader("User-Agent", agent)
date_connection.putheader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
date_connection.putheader("Accept-Language", "it-it,it;q=0.8,en-us;q=0.5,en;q=0.3")
date_connection.putheader("Accept-Encoding", "gzip,deflate")
date_connection.putheader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
date_connection.putheader("Connection", "keep-alive")
date_connection.putheader("Keep-Alive", "115")
date_connection.endheaders()
date_response = date_connection.getresponse().read()
date_connection.close();
return bytes.decode(date_response[:len(date_response)-1])
def raiPrograms(host, chan_name):
if chan_name == "RaiQuattro": chan_name = "Rai4"
if chan_name == "RaiSport+": chan_name = "RaiSportSatellite"
if chan_name == "RaiStoria": chan_name = "RAIEDU2"
if chan_name == "RaiSatExtra": chan_name = "Extra"
if chan_name == "RaiSatPremium": chan_name = "Premium"
if chan_name == "RaiSatCinema": chan_name = "CinemaWorld"
if chan_name == "RaiSatYoyo": chan_name = "Yoyo"
xml_connection = client.HTTPConnection(host)
xml_connection.putrequest("GET", "/dl/portale/html/palinsesti/static/"+chan_name+".html")
xml_connection.putheader("User-Agent", agent)
xml_connection.putheader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
xml_connection.putheader("Accept-Language", "it-it,it;q=0.8,en-us;q=0.5,en;q=0.3")
xml_connection.putheader("Accept-Encoding", "gzip,deflate")
xml_connection.putheader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
xml_connection.putheader("Keep-Alive", "115")
xml_connection.putheader("Connection", "keep-alive")
xml_connection.endheaders()
xml_response = xml_connection.getresponse().read()
xml_connection.close()
return str(gzip.GzipFile(fileobj=io.BytesIO(xml_response)).read(), "utf8")
def encode1(token):
rnd = random.randint(0,10)
return ''.join(chr(ord(ch) ^ rnd) for ch in token) + ";" + str(rnd)
def encode2(token, key="hMrxuE2T8V0WRW0VmHaKMoFwy1XRc+hK7eBX2tTLVTw="):
return encode2b(token, key)
#DEPRECATED
def encode2a(token, key="hMrxuE2T8V0WRW0VmHaKMoFwy1XRc+hK7eBX2tTLVTw="):
encoded = ""
i, j, lenkey = 0, 0, len(key)
for ch in token:
encoded += chr(ord(token[i]) ^ ord(key[j]))
i, j = (i+1), (j+1)%lenkey
return encoded
def encode2b(token, key="hMrxuE2T8V0WRW0VmHaKMoFwy1XRc+hK7eBX2tTLVTw="):
encoded = io.StringIO()
i, j, lenkey = len(token)-1, 0, len(key)
for ch in token:
encoded.write(chr(ord(token[i]) ^ ord(key[j])))
i, j = (i-1), (j+1)%lenkey
return encoded.getvalue()[::-1]
#DEPRECATED
def encode2c(token, key = "hMrxuE2T8V0WRW0VmHaKMoFwy1XRc+hK7eBX2tTLVTw="):
length = len(token)
encoded = list("" for i in range(0, length))
pool = list(chr(i) for i in range(0, 256))
j = 0
for i in range(0, 256):
j = (j + ord(pool[i]) + ord(key[i%length])) % 256
pool[i], pool[j] = pool[j], pool[i]
j, index = 0, 0
for i in range(0, length):
index = (index+1) % 256
j = (j + ord(pool[index])) % 256;
pool[index], pool[j] = pool[j], pool[index]
k = (ord(pool[index]) + ord(pool[j])) % 256;
encoded[i] = chr(ord(token[i]) ^ ord(pool[k]))
return ''.join(i for i in encoded)
def encode3(token):
return base64.encodebytes(str.encode(token)).decode()
def authCode(chan):
re_date = "^(?P<day>\d*)-(?P<month>\d*)-(?P<year>\d*)\s(?P<hour>\d*):(?P<minutes>\d*):(?P<seconds>\d*)"
match_date = re.match(re_date, raiDate()).groupdict()
day, month, year = match_date["day"], match_date["month"], match_date["year"]
hour, minutes, seconds = match_date["hour"], match_date["minutes"], match_date["seconds"]
rnd1 = str(random.randint(0, 1234))
rnd2 = str(random.randint(0, 1234))
token = year+";"+chan+";"+day+"-"+month+"-"+rnd1+"-"+hour+"-"+minutes+"-"+seconds+"-"+rnd2
return encode3(encode2(encode1(token)))
def arguments():
global stream, chan_name
global isVoD, isProgram
args = sys.argv[1:]
for arg in args:
if arg.startswith("-"):
match_parm = re.match("^-(\w*)=(.*)", arg)
if type(match_parm).__name__ == "NoneType":
print("WARNING: "+arg+" is not a valid argument")
continue
if match_parm.groups()[0] == "vlcdir":
vlc_dir = match_parm.groups()[1]
elif match_parm.groups()[0] == "uagent":
agent = match_parm.groups()[1]
elif match_parm.groups()[0] == "ttAuth":
ttAuth = match_parm.groups()[1]
elif match_parm.groups()[0] == "progs":
progs_file = match_parm.groups()[1]
isPrograms = True
else:
print("WARNING: unknown argument ("+match_parm.groups()[0]+")")
else:
try:
stream = urls[arg]
chan_name = arg
isVoD = False
except:
stream = videoURL(arg)
isVoD = True
isPrograms = False
break
def playerURL():
arguments()
global stream
global isVoD
if isVoD == False:
return streamURL(stream)
else:
return stream
if __name__ == '__main__':
if isPrograms == True:
xml_file = open(progs_file, "w")
xml_file.write(raiPrograms("www.rai.tv", chan_name))
xml_file.close()
subprocess.Popen([vlc_dir+"/vlc", "--http-user-agent=\""+agent+"\"", playerURL()])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment