예제 #1
0
class API(object):
    def new_session(self):
        self.logged_in = False
        self._session = Session(HEADERS)
        self._set_authentication()

    def _set_authentication(self):
        token = userdata.get('access_token')
        if not token:
            return

        self._session.headers.update({'sky-x-access-token': token})
        self.logged_in = True

    def series(self, id):
        return self._session.get(CONTENT_URL + id).json()

    def content(self, section='', sortby='TITLE', text='', title=None, channels='', start=0):
        params = {
            'title': title or '',
            'genre': '',
            'rating': '',
            'text': text,
            'sortBy': sortby,
            'lastChance': 'true' if sortby == 'LASTCHANCE' else 'false',
            'type': '',
            'channel': channels,
            'section': section,
            'size': 100,
            'start': start,
        }

        return self._session.get(CONTENT_URL, params=params).json()

    def channels(self):
        data = self._session.get(CHANNELS_URL).json()
        return data['entries']
        
    def login(self, username, password):
        device_id = hashlib.md5(username).hexdigest()

        data = {
            "deviceDetails": "test",
            "deviceID": device_id,
            "deviceIP": DEVICE_IP,
            "password": password,
            "username": username
        }

        resp = self._session.post(AUTH_URL, json=data)
        data = resp.json()
        if resp.status_code != 200 or 'sessiontoken' not in data:
            raise APIError(_(_.LOGIN_ERROR, message=data.get('message')))

        userdata.set('access_token', data['sessiontoken'])
        userdata.set('device_id', device_id)

        if settings.getBool('save_password', False):
            userdata.set('pswd', password)

        self._set_authentication()

        data = self._session.get(SUBSCRIPTIONS_URL.format(data['profileId'])).json()
        userdata.set('subscriptions', data['onlineSubscriptions'])

    def _renew_token(self):
        password = userdata.get('pswd')

        if password:
            self.login(userdata.get('username'), password)
            return

        data = {
            "deviceID": userdata.get('device_id'),
            "deviceIP": DEVICE_IP,
            "sessionToken": userdata.get('access_token'),
        }

        resp = self._session.post(RENEW_URL, json=data)
        data = resp.json()

        if resp.status_code != 200 or 'sessiontoken' not in data:
            raise APIError(_(_.RENEW_TOKEN_ERROR, message=data.get('message')))

        userdata.set('access_token', data['sessiontoken'])

        self._set_authentication()

    def _get_play_token(self):
        self._renew_token()

        params = {
            'profileId':   userdata.get('device_id'),
            'deviceId':    userdata.get('device_id'),
            'partnerId':   'skygo',
            'description': 'ANDROID',
        }

        resp = self._session.get(TOKEN_URL, params=params)
        data = resp.json()

        if resp.status_code != 200 or 'token' not in data:
            raise APIError(_(_.TOKEN_ERROR, message=data.get('message')))

        return data['token']

    def play_media(self, id):
        token = self._get_play_token()

        params = {
            'form': 'json',
            'types': None,
            'fields': 'id,content',
            'byId': id,
        }

        data = self._session.get(PLAY_URL, params=params).json()

        videos = data['entries'][0]['media$content']

        chosen = videos[0]
        for video in videos:
            if video['plfile$format'] == 'MPEG-DASH':
                chosen = video
                break
 
        url     = '{}&auth={}&formats=mpeg-dash&tracking=true'.format(chosen['plfile$url'], token)
        pid     = chosen['plfile$url'].split('?')[0].split('/')[-1]
        license = WIDEVINE_URL.format(token=token, pid=pid, challenge='B{SSM}')

        url = self._get_location(url)

        return url, license

    def _get_location(self, url):
        resp = self._session.get(url, allow_redirects=False)

        if resp.status_code != 302:
            data = resp.json()
            raise APIError(_(_.PLAY_ERROR, message=data.get('description')))

        url = resp.headers.get('location')
        if 'faxs' in url:
            raise APIError(_.ADOBE_ERROR)

        return url

    def play_channel(self, id):
        token = self._get_play_token()
        url = PLAY_CHANNEL_URL.format(id=id, auth=token)

        url = self._get_location(url)

        return url

    def epg(self, ids, start=None, end=None):
        start = start or arrow.utcnow()
        end   = end   or start.shift(days=1)

        params = {
            'startTimestamp': '{}000'.format(start.timestamp),
            'endTimestamp':   '{}000'.format(end.timestamp),
            'channelIds':     ','.join(ids),
        }

        return self._session.get(EPG_URL, params=params).json()['events']

    def logout(self):
        userdata.delete('device_id')
        userdata.delete('access_token')
        userdata.delete('pswd')
        userdata.delete('subscriptions')
        self.new_session()
예제 #2
0
파일: api.py 프로젝트: fadifadisadi/LilacTV
class API(object):
    def new_session(self):
        self.logged_in = False

        self._session = Session(HEADERS)
        self._set_authentication()

    def _set_authentication(self):
        access_token = userdata.get('access_token')
        if not access_token:
            return

        self._session.headers.update(
            {'authorization': 'Bearer {}'.format(access_token)})
        self.logged_in = True

    def _oauth_token(self, data):
        token_data = self._session.post(
            'https://auth.kayosports.com.au/oauth/token', json=data).json()
        if 'error' in token_data:
            raise APIError(
                _(_.LOGIN_ERROR, msg=token_data.get('error_description')))

        account_status = None
        try:
            b64_string = token_data['access_token'].split('.')[1]
            b64_string += "=" * ((4 - len(b64_string) % 4) % 4)  #fix padding

            data = json.loads(b64decode(b64_string))
            account_status = data['https://kayosports.com.au/status'][
                'account_status']
        except:
            log.debug('Failed to get account status')

        if account_status and account_status != 'ACTIVE_SUBSCRIPTION':
            raise APIError(_.INVALID_SUBSCRIPTION)

        userdata.set('access_token', token_data['access_token'])
        userdata.set('expires', int(time() + token_data['expires_in'] - 15))

        if 'refresh_token' in token_data:
            userdata.set('refresh_token', token_data['refresh_token'])

        self._set_authentication()

    def _refresh_token(self):
        if userdata.get('expires', 0) > time():
            return

        payload = {
            "refresh_token": userdata.get('refresh_token'),
            "grant_type": "refresh_token",
            "client_id": CLIENTID,
        }

        self._oauth_token(payload)

    def login(self, username, password):
        payload = {
            "audience": "kayosports.com.au",
            "grant_type": "http://auth0.com/oauth/grant-type/password-realm",
            "scope": "openid offline_access",
            "realm": "prod-martian-database",
            "client_id": CLIENTID,
            "username": username,
            "password": password,
        }

        self._oauth_token(payload)

    def profiles(self):
        self._refresh_token()
        return self._session.get(
            'https://profileapi.kayosports.com.au/user/profile').json()

    def sport_menu(self):
        return self._session.get(
            'https://resources.kayosports.com.au/production/sport-menu/lists/default.json'
        ).json()

    def cdn_selection(self, media_type):
        return self._session.get(
            'https://cdnselectionserviceapi.kayosports.com.au/android/usecdn/mobile/{}'
            .format(media_type)).json().get('useCDN')

    #landing has heros and panels
    def landing(self, name, **kwargs):
        params = {
            'evaluate': 99,
            'resourcesEnv': 'production',
            'chromecastEnv': 'production',
            'statsEnv': 'production',
        }

        params.update(**kwargs)

        return self._session.get(
            'https://vccapi.kayosports.com.au/content/types/landing/names/{}'.
            format(name),
            params=params).json()

    #panel has shows and episodes
    def panel(self, id, **kwargs):
        params = {
            'evaluate': 3,
        }

        params.update(**kwargs)

        return self._session.get(
            'https://vccapi.kayosports.com.au/content/types/carousel/keys/{}'.
            format(id),
            params=params).json()[0]

    #show has episodes and panels
    def show(self, show_id, season_id=None, **kwargs):
        params = {
            'evaluate': 3,
            'showCategory': show_id,
            'seasonCategory': season_id,
        }

        params.update(**kwargs)

        return self._session.get(
            'https://vccapi.kayosports.com.au/content/types/landing/names/show',
            params=params).json()

    def event(self, id, **kwargs):
        params = {
            'evaluate': 3,
            'event': id,
        }

        params.update(**kwargs)

        return self._session.get(
            'https://vccapi.kayosports.com.au/content/types/landing/names/event',
            params=params).json()[0]['contents'][0]['data']['asset']

    def stream(self, asset):
        self._refresh_token()

        params = {
            'fields': 'alternativeStreams',
        }

        data = self._session.post(
            'https://vmndplay.kayosports.com.au/api/v1/asset/{}/play'.format(
                asset),
            params=params,
            json={}).json()
        if 'errors' in data:
            raise APIError(_(_.ASSET_ERROR, msg=data['errors'][0]['detail']))

        return data['data'][0]

    def logout(self):
        userdata.delete('access_token')
        userdata.delete('refresh_token')
        userdata.delete('expires')
        userdata.delete('profile')
        self.new_session()
예제 #3
0
class API(object):
    def new_session(self):
        self.logged_in = False

        self._session = Session(HEADERS)
        self._set_authentication()

    def _set_authentication(self):
        access_token = userdata.get('access_token')
        if not access_token:
            return

        self._session.headers.update({'authorization': 'Bearer {}'.format(access_token)})
        self.logged_in = True

    def _oauth_token(self, data):
        token_data = self._session.post('https://auth.kayosports.com.au/oauth/token', json=data).json()
        if 'error' in token_data:
            raise APIError(_(_.LOGIN_ERROR, msg=token_data.get('error_description')))

        userdata.set('access_token', token_data['access_token'])
        userdata.set('expires', int(time() + token_data['expires_in'] - 15))

        if 'refresh_token' in token_data:
            userdata.set('refresh_token', token_data['refresh_token'])

        self._set_authentication()

    def _refresh_token(self):
        if userdata.get('expires', 0) > time():
            return

        payload = {
            "refresh_token": userdata.get('refresh_token'),
            "grant_type": "refresh_token",
            "client_id": CLIENTID,
        }

        self._oauth_token(payload)

    def login(self, username, password):
        payload = {
            "audience": "kayosports.com.au",
            "grant_type": "http://auth0.com/oauth/grant-type/password-realm",
            "scope": "openid offline_access",
            "realm": "prod-martian-database",
            "client_id": CLIENTID,
            "username": username,
            "password": password,
        }

        self._oauth_token(payload)

    def profiles(self):
        self._refresh_token()
        return self._session.get('https://profileapi.kayosports.com.au/user/profile').json()


    #landing has heros and panels
    def landing(self, name):
        params = {
            'evaluate': 99, 
            'profile': userdata.get('profile'),
        }

        return self._session.get('https://vccapi.kayosports.com.au/content/types/landing/names/{}'.format(name), params=params).json()

    #panel has shows and episodes
    def panel(self, id):
        params = {
            #'evaluate': 3, 
            'profile': userdata.get('profile'),
        }

        return self._session.get('https://vccapi.kayosports.com.au/content/types/carousel/keys/{}'.format(id), params=params).json()[0]

    #show has episodes and panels
    def show(self, id):
        params = {
            'evaluate': 99, 
            'profile': userdata.get('profile'),
            'showCategory': id,
        }

        return self._session.get('https://vccapi.kayosports.com.au/content/types/landing/names/show', params=params).json()

    def event(self, id):
        params = {
            'evaluate': 1, 
            'profile': userdata.get('profile'),
            'event': id,
        }

        return self._session.get('https://vccapi.kayosports.com.au/content/types/landing/names/event', params=params).json()[0]['contents'][0]['data']['asset']

    def sport(self, sport=None):
        params = {
            'evaluate': 99, 
            'profile': userdata.get('profile'),
            'sport': sport, 
        }

        return self._session.get('https://vccapi.kayosports.com.au/content/types/landing/names/sport', params=params).json()

    def sport_menu(self, sport):
        return self._session.get('https://resources.kayosports.com.au/production/sport-menu/lists/{}.json'.format(sport)).json()

    def stream(self, asset):
        self._refresh_token()

        params = {
            'fields': 'alternativeStreams',
        }

        data = self._session.post('https://vmndplay.kayosports.com.au/api/v1/asset/{}/play'.format(asset), params=params, json={}).json()
        if 'errors' in data:
            raise APIError(_(_.ASSET_ERROR, msg=data['errors'][0]['detail']))

        return data['data'][0]

    def logout(self):
        userdata.delete('access_token')
        userdata.delete('refresh_token')
        userdata.delete('expires')
        userdata.delete('profile')
        self.new_session()
예제 #4
0
class API(object):
    def new_session(self):
        self.logged_in = False
        self._session = Session(HEADERS, base_url=API_URL)
        self._set_authentication()

    def _set_authentication(self):
        access_token = userdata.get('token')
        if not access_token:
            return

        self._session.headers.update({'X-Auth-Token': access_token})
        self.logged_in = True

    def login(self, username, password):
        self.logout()

        payload = {
            'email': username,
            'password': password,
            'platform': 'google',
        }

        data = self._session.post('/v1/login/', data=payload).json()
        if 'error' in data:
            try:
                msg = data['error']['message']['base'][0]
            except:
                msg = ''

            raise APIError(_(_.LOGIN_ERROR, msg=msg))

        userdata.set('token', data['message']['auth_token'])
        self._set_authentication()

    @mem_cache.cached(CACHE_TIME)
    def categories(self):
        return self._session.get('/v1/categories').json()['data']

    def series(self, id):
        return self._session.get('/v2/series/{}'.format(id)).json()['data']

    @mem_cache.cached(CACHE_TIME)
    def featured(self):
        return self._session.get('/v2/featured').json()

    def sections(self, id, page=1):
        params = {
            'cache': False,
            'collections': True,
            'media_limit': 36,
            'page': page,
        }

        return self._session.get(
            '/v1/sections/{}/mobile'.format(id)).json()['data']['groups']

    def collection(self, id, flattened=False):
        params = {
            'flattened': flattened,
        }

        return self._session.get('/v2/collections/{}'.format(id),
                                 params=params).json()['data']

    @mem_cache.cached(CACHE_TIME)
    def collections(self, flattened=False, excludeMedia=True, page=1):
        params = {
            'flattened': flattened,
            'excludeMedia': excludeMedia,
            'limit': 20,
            'page': page,
        }

        return self._session.get('/v2/collections', params=params).json()

    def filter_media(self, filterby, term=None, collections=True, page=1):
        params = {
            'filterBy': filterby,
            'collections': collections,
            'limit': 20,
            'page': page,
        }

        if term:
            params['term'] = term

        return self._session.get('/v1/media', params=params).json()

    def set_user_media(self, id, **kwargs):
        params = {
            'media_id': id,
            #'is_bookmarked': 'true' if value else 'false',
        }

        params.update(kwargs)

        data = self._session.post('/v1/user_media', params=params,
                                  json={}).json()
        print(data)

    def get_subtitles(self, captions):
        subtitles = []

        for idx, caption in enumerate(captions):
            try:
                r = self._session.get(caption['file'])
                reader = detect_format(r.text)
                srt = SRTWriter().write(reader().read(r.text))
            except:
                log.debug('Failed to parse subtitle: {}'.format(
                    caption['file']))
            else:
                srtfile = xbmc.translatePath(
                    'special://temp/curiosity{}.{}.srt'.format(
                        idx, caption['code'])).decode('utf-8')

                with codecs.open(srtfile, "w", "utf-8") as f:
                    f.write(srt)

                subtitles.append(srtfile)

        return subtitles

    def media(self, id):
        # params = {
        #    'showEncodings': 'Android', #limits to 1080p
        #    'encodingsNew': 'true', #breaks playback
        # }

        return self._session.get('/v1/media/{}'.format(id)).json()['data']

    def logout(self):
        userdata.delete('token')
        mem_cache.empty()
        self.new_session()
예제 #5
0
class API(object):
    def new_session(self):
        self.logged_in = False
        self._session = Session(HEADERS, base_url=API_URL)
        self.set_access_token(userdata.get('access_token'))

    def set_access_token(self, token):
        if token:
            self._session.headers.update(
                {'Authorization': 'Bearer {0}'.format(token)})
            self.logged_in = True

    def login(self, username, password):
        log('API: Login')

        data = {'response_type': 'token', 'lang': 'eng'}

        resp = self._session.get(LOGIN_URL, params=data)
        soup = BeautifulSoup(resp.text, 'html.parser')

        form = soup.find('form', id='new_signin')
        for e in form.find_all('input'):
            data[e.attrs['name']] = e.attrs.get('value')

        data.update({
            'signin[email]': username,
            'signin[password]': password,
        })

        resp = self._session.post(LOGIN_URL, data=data, allow_redirects=False)
        access_token = resp.cookies.get('showmax_oauth')

        if not access_token:
            self.logout()
            raise Error()

        self.set_access_token(access_token)

        data = self._session.get('user/current', params={'lang': 'eng'}).json()
        if 'error_code' in data:
            raise Error()

        device_id = hashlib.sha1(username).hexdigest().upper()

        userdata.set('device_id', device_id)
        userdata.set('access_token', access_token)
        userdata.set('user_id', data['user_id'])

    def catalogue(self, _params):
        def process_page(start):
            params = {
                'field[]': [
                    'id', 'images', 'title', 'items', 'total', 'type',
                    'description', 'videos'
                ],
                'lang':
                'eng',
                'showmax_rating':
                'adults',
                'sort':
                'alphabet',
                'start':
                start,
                'subscription_status':
                'full'
            }

            params.update(_params)

            data = self._session.get('catalogue/assets', params=params).json()
            items = data['items']

            count = int(data.get('count', 0))
            remaining = int(data.get('remaining', 0))
            if count > 0 and remaining > 0:
                items.extend(process_page(start + count))

            return items

        return process_page(start=0)

    def shows(self):
        return self.catalogue({
            'type': 'tv_series',
            'exclude_section[]': ['kids'],
        })

    def movies(self):
        return self.catalogue({
            'type': 'movie',
            'exclude_section[]': ['kids'],
        })

    def kids(self):
        return self.catalogue({
            'section': 'kids',
        })

    def show(self, show_id):
        params = {
            'field[]': [
                'id', 'images', 'title', 'items', 'total', 'type',
                'description', 'videos', 'number', 'seasons', 'episodes'
            ],
            'lang':
            'eng',
            'showmax_rating':
            'adults',
            'subscription_status':
            'full'
        }

        return self._session.get('catalogue/tv_series/{}'.format(show_id),
                                 params=params).json()

    def search(self, query):
        return self.catalogue({
            'q': query,
        })

    def logout(self):
        log('API: Logout')
        userdata.delete('device_id')
        userdata.delete('access_token')
        userdata.delete('user_id')
        self.new_session()

    def play(self, video_id):
        params = {
            'encoding': 'mpd_widevine_modular',
            'subscription_status': 'full',
            'lang': 'eng',
        }

        data = self._session.get('playback/play/{0}'.format(video_id),
                                 params=params).json()

        url = data['url']
        task_id = data['packaging_task_id']
        session_id = data['session_id']

        data = {
            'user_id': userdata.get('user_id'),
            'video_id': video_id,
            'hw_code': userdata.get('device_id'),
            'packaging_task_id': task_id,
            'session_id': session_id,
        }

        params = {'showmax_rating': 'adults', 'lang': 'eng'}
        data = self._session.post('playback/verify', params=params,
                                  data=data).json()

        license_request = data['license_request']
        license_url = API_URL.format(
            'drm/widevine_modular?license_request={0}'.format(license_request))

        return url, license_url