Skip to content

Instantly share code, notes, and snippets.

@pisculichi
Last active December 3, 2018 03:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pisculichi/25be9225fd864458b4f0ce8f993e8ef0 to your computer and use it in GitHub Desktop.
Save pisculichi/25be9225fd864458b4f0ce8f993e8ef0 to your computer and use it in GitHub Desktop.
Dado el identificador de una película, documental o episodio de una serie en odeon.com.ar este script devuelve el enlace de streaming para ser utilizado en reproductores que soporten M3U8 (por ejemplo, VLC).
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys
from collections import namedtuple
try:
# Python 3
from urllib.parse import urlparse, urlunparse, urljoin
except ImportError:
# Python 2
from urlparse import urlparse, urlunparse, urljoin
import execjs
import m3u8
import requests
from pyquery import PyQuery
def login(user, password):
odeon_session = requests.Session()
login_data = {
'email': user,
'password': password
}
login_headers = {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
login_req = odeon_session.post(
'https://id.odeon.com.ar/v1.2/auth/login',
headers=login_headers,
json=login_data,
)
user_token = login_req.json().get('token', '')
UserSession = namedtuple('UserSession', ['session', 'token'])
return UserSession(odeon_session, user_token)
def get_user_profile(user_session):
session, token = user_session
perfil_headers = {
'Accept': 'application/json, text/plain, */*',
'Authorization': 'Bearer {}'.format(token),
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
perfil_req = session.get(
'https://www.odeon.com.ar/api/v1.4/user',
headers=perfil_headers,
)
perfiles_info = perfil_req.json()['perfiles']
return perfiles_info
def get_movie_profile(user_session, movie_id):
user_id = get_user_profile(user_session)[0].get('id', '')
session, token = user_session
movie_profile_url = 'https://www.odeon.com.ar/api/v1/INCAA/prod/{}'.format(movie_id)
movie_profile_headers = {
'Accept': 'application/json, text/plain, */*',
'Authorization': 'Bearer {}'.format(token),
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/json; charset=utf-8',
'Pragma': 'no-cache',
'Referer': 'https://www.odeon.com.ar/',
'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
movie_profile_params = {
'perfil': user_id,
}
movie_profile_req = session.get(
movie_profile_url,
headers=movie_profile_headers,
params=movie_profile_params,
)
movie_profile_info = movie_profile_req.json()
return movie_profile_info
def get_streaming_link(user_session, movie_id):
user_id = get_user_profile(user_session)[0].get('id', '')
session, token = user_session
movie_player_params = {
'i': movie_id,
'p': user_id,
's': 'INCAA',
't': token,
}
movie_player_headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, sdch',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Host': 'player.odeon.com.ar',
'Pragma': 'no-cache',
'Referer': 'https://www.odeon.com.ar/',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
movie_player_cookies = {
'jwplayer.captionLabel': 'Off',
}
movie_player_req = session.get(
'https://player.odeon.com.ar/odeon',
headers=movie_player_headers,
params=movie_player_params,
cookies=movie_player_cookies,
)
html_dom = PyQuery(movie_player_req.text)
#print(html_dom)
wms_funs_js1 = html_dom('script')[1].text
wms_funs_js2 = html_dom('script')[2].text
# print(wms_funs_js1)
# print(wms_funs_js2)
node = execjs.get("Node")
wms_funs_js1_com = node.compile(wms_funs_js1)
real_fun = wms_funs_js2.split(";")[1]
result = wms_funs_js1_com.eval(real_fun)
wms = result.split("&")[1]
rtsp_link = html_dom('p').filter('#rtspLink').find('a').attr.href
# Fix rtsp link
rtsp_link = rtsp_link.replace('.smil/', '/media.smil/')
return rtsp_link + wms
def get_variant_streams_playlist(user_session, rtsp_link):
session, token = user_session
url_parse = urlparse(rtsp_link)
m3u8_playlist_headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, sdch',
'Host': url_parse.netloc,
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Pragma': 'no-cache',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
m3u8_main_playlist_req = session.get(
rtsp_link,
headers=m3u8_playlist_headers,
)
m3u8_variant_streams = m3u8.loads(m3u8_main_playlist_req.text)
return m3u8_variant_streams
def get_chunklist_playlist(playlist, quality=None):
stream_chunklist = None
if not playlist.is_variant:
for chunklist in playlist.playlists:
return chunklist.uri
if quality is None:
max_bw = 0
# TODO: Improve this ugly for-loop
for chunklist in playlist.playlists:
if chunklist.stream_info.bandwidth > max_bw:
max_bw = chunklist.stream_info.bandwidth
stream_chunklist = chunklist
else:
# TODO: Improve this ugly for-loop
for chunklist in playlist.playlists:
if chunklist.stream_info.bandwidth == quality:
stream_chunklist = chunklist
break
return stream_chunklist
def build_stream_url(rtsp_link, chunklist_url):
return urljoin(rtsp_link, chunklist_url)
if __name__ == '__main__':
# Usage:
# $ pyodeon.py your_email your_password movie_id_you_want_to_watch | vlc -
#
user, password, movie_id = sys.argv[1:4] # TODO: Improve args parsing
user_session = login(user, password)
user_profile = get_user_profile(user_session)
movie_profile = get_movie_profile(user_session, movie_id)
rtsp_link = get_streaming_link(user_session, movie_id)
m3u8_variant_streams = get_variant_streams_playlist(user_session, rtsp_link)
chunklist = get_chunklist_playlist(m3u8_variant_streams)
try:
stream_url = build_stream_url(rtsp_link, chunklist)
except AttributeError:
stream_url = build_stream_url(rtsp_link, chunklist)
stream_url = stream_url.replace('media/','')
print(stream_url, end='')
lxml~=3.5.0
m3u8~=0.2.8
pyquery~=1.2.9
requests~=2.8.1
simplejson~=3.8.1
@pisculichi
Copy link
Author

Hace falta tener NodeJS para poder ejecutar javascript con PyExecJS con resultado satisfactorio.

@vzreagle
Copy link

vzreagle commented Sep 5, 2017

Hola, se podrá aplicar en KODI?
Saludos,

@maferv
Copy link

maferv commented Dec 3, 2018

Muy buen laburo. Lo actualizaste para cinear?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment