""" This is shamelessly taken from mlbstreamer https://github.com/tonycpsu/mlbstreamer because I didn't want to reinvent the login/auth/cookie management (code is modified somewhat arbitrarily. Changed to reduce some imports, and some just to simplify for my own understanding.) Thanks tonycpsu! """ import abc import datetime import json import logging import os import requests import time import http.cookiejar import dateutil.parser import mlbv.mlbam.common.config as config import mlbv.mlbam.common.util as util LOG = logging.getLogger(__name__) SESSION_FILE = os.path.join(config.CONFIG.dir, "session") COOKIE_FILE = os.path.join(config.CONFIG.dir, 'cookies') class SessionException(Exception): pass class Session(object): def __init__(self, user_agent, token_url_template, platform): self.user_agent = user_agent self.token_url_template = token_url_template self.platform = platform self.session = requests.Session() self.session.cookies = http.cookiejar.LWPCookieJar() if not os.path.exists(COOKIE_FILE): self.session.cookies.save(COOKIE_FILE) self.session.cookies.load(COOKIE_FILE, ignore_discard=True) self.session.headers = {"User-agent": user_agent} if os.path.exists(SESSION_FILE): self.load() else: self._state = { 'api_key': None, 'client_api_key': None, 'token': None, 'access_token': None, 'access_token_expiry': None } self.login() def __getattr__(self, attr): if attr in ["delete", "get", "head", "options", "post", "put", "patch"]: return getattr(self.session, attr) raise AttributeError(attr) def destroy(self): if os.path.exists(COOKIE_FILE): os.remove(COOKIE_FILE) if os.path.exists(SESSION_FILE): os.remove(SESSION_FILE) def load(self): with open(SESSION_FILE) as infile: self._state = json.load(infile) def save(self): with open(SESSION_FILE, 'w') as outfile: json.dump(self._state, outfile) self.session.cookies.save(COOKIE_FILE) @abc.abstractmethod def login(self): return @abc.abstractmethod def is_logged_in(self): return False def get_cookie_dict(self): return requests.utils.dict_from_cookiejar(self.session.cookies) def get_cookie(self, name): return self.get_cookie_dict().get(name) @property def ipid(self): return self.get_cookie('ipid') @property def fingerprint(self): return self.get_cookie('fprt') @property def api_key(self): if self._state['api_key'] is None: self.update_api_keys() return self._state['api_key'] @property def client_api_key(self): if self._state['client_api_key'] is None: self.update_api_keys() return self._state['client_api_key'] @abc.abstractmethod def update_api_keys(self): return @property def token(self): LOG.debug("getting token") if self._state['token'] is None: headers = {"x-api-key": self.api_key} response = self.session.get(self.token_url_template.format(ipid=self.ipid, fingerprint=self.fingerprint, platform=self.platform), headers=headers) self._state['token'] = response.text return self._state['token'] @token.setter def token(self, value): self._state['token'] = value @property def access_token_expiry(self): if self._state['access_token_expiry'] is not None: return dateutil.parser.parse(str(self._state['access_token_expiry'])) return None @access_token_expiry.setter def access_token_expiry(self, val): if val: self._state['access_token_expiry'] = val.isoformat() @property def access_token(self): LOG.debug("getting access token") if not self._state['access_token'] or not self.access_token_expiry or \ self.access_token_expiry < datetime.datetime.now(tz=datetime.timezone.utc): try: self._state['access_token'], self.access_token_expiry = self.get_access_token() except requests.exceptions.HTTPError: # Clear token and then try to get a new access_token self.token = None self._state['access_token'], self.access_token_expiry = self.get_access_token() self.save() LOG.debug("access_token: %s", self._state['access_token']) return self._state['access_token'] @abc.abstractmethod def get_access_token(self): return None @abc.abstractmethod def lookup_stream_url(self, game_pk, media_id): return None def save_playlist_to_file(self, stream_url): headers = { "Accept": "*/*", "Accept-Encoding": "identity", "Accept-Language": "en-US,en;q=0.8", "Connection": "keep-alive", "User-Agent": self.user_agent, "Cookie": self.access_token } # util.log_http(stream_url, 'get', headers, sys._getframe().f_code.co_name) resp = self.session.get(stream_url, headers=headers) playlist = resp.text playlist_file = os.path.join(util.get_tempdir(), 'playlist-{}.m3u8'.format(time.strftime("%Y-%m-%d"))) LOG.info('Writing playlist to: %s', playlist_file) with open(playlist_file, 'w') as outf: outf.write(playlist) LOG.debug('save_playlist_to_file: %s', playlist)