Created
March 3, 2010 07:44
-
-
Save anonymous/320415 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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