Пример #1
0
    def new_session(self):
        self.logged_in = False

        self._session = Session(HEADERS)
        self._set_authentication()
        
        settings.setBool('_logged_in', self.logged_in)
Пример #2
0
def process(item, item_type):
    if item.path_type == Source.TYPE_ADDON:
        _opath = sys.path[:]
        _ocwd = os.getcwd()

        try:
            addons_path = xbmc.translatePath('special://home/addons').decode(
                "utf-8")
            addon_path = os.path.join(addons_path, item.path)

            os.chdir(addon_path)
            sys.path.insert(0, addon_path)
            os.environ['ADDON_ID'] = item.path

            f, filename, description = imp.find_module(item.path,
                                                       [addons_path])
            package = imp.load_module(item.path, f, filename, description)

            f, filename, description = imp.find_module(MERGE_MODULE,
                                                       package.__path__)
            try:
                module = imp.load_module(
                    '{}.{}'.format(item.path, MERGE_MODULE), f, filename,
                    description)

                if item_type == Source.PLAYLIST:
                    method = getattr(module, METHOD_PLAYLIST)
                elif item_type == Source.EPG:
                    method = getattr(module, METHOD_EPG)

                return method()
            finally:
                f.close()
        finally:
            sys.path = _opath
            os.chdir(_ocwd)
            os.environ.pop('ADDON_ID', None)
            for m in sys.modules.keys():
                if m.startswith(item.path):
                    del (sys.modules[m])

    elif item.path_type == Source.TYPE_REMOTE:
        r = Session().get(item.path, stream=True)
        r.raise_for_status()
        in_file = StringIO.StringIO(r.content)

    elif item.path_type == Source.TYPE_LOCAL:
        in_file = open(xbmc.translatePath(item.path))

    if item.file_type == Source.FILE_GZIP:
        in_file = gzip.GzipFile(fileobj=in_file)

    return in_file.read()
Пример #3
0
def dns4me_login(**kwargs):
    username = gui.input('dns4me Username').strip()
    if not username:
        return

    password = gui.input('dns4me Password', hide_input=True).strip()
    if not password:
        return

    data = Session().post('https://dns4me.net/api/v2/get_apikey',
                          data={
                              'username': username,
                              'password': password
                          }).json()
    if 'apikey' in data:
        userdata.set('dns4me_key', data['apikey'])
    else:
        plugin.exception('Failed to login')

    gui.refresh()
Пример #4
0
def process_file(item, method_name, file_path):
    if item.path_type == Source.TYPE_ADDON:
        addon = xbmcaddon.Addon(item.path)
        addon_id = addon.getAddonInfo('id')
        addon_path = xbmc.translatePath(addon.getAddonInfo('path'))
        merge_path = os.path.join(addon_path, MERGE_SETTING_FILE)

        with open(merge_path) as f:
            data = json.load(f)

        item.path = data[method_name].replace('$ID', addon_id).replace(
            '$FILE', file_path)

        if item.path.lower().startswith('plugin'):
            call_addon_method(item.path)
            return

        if item.path.lower().startswith('http'):
            item.path_type = Source.TYPE_REMOTE
        else:
            item.path_type = Source.TYPE_LOCAL

        if item.path.lower().endswith('.gz'):
            item.file_type = Source.FILE_GZIP

    if item.path_type == Source.TYPE_REMOTE:
        log.debug('Downloading: {} > {}'.format(item.path, file_path))
        Session().chunked_dl(item.path, file_path)

    elif item.path_type == Source.TYPE_LOCAL:
        path = xbmc.translatePath(item.path)
        if not os.path.exists(path):
            raise Error(_(_.LOCAL_PATH_MISSING, path=path))

        log.debug('Copying local file: {} > {}'.format(path, file_path))
        shutil.copyfile(path, file_path)

    if item.file_type == Source.FILE_GZIP:
        gzip_extract(file_path)
Пример #5
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()
Пример #6
0
def playlist(output, **kwargs):
    Session().chunked_dl(PLAYLIST_URL, output)
Пример #7
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')))

        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()
Пример #8
0
def epg(output, **kwargs):
    Session().chunked_dl(EPG_URL.format(region=get_region()), output)
Пример #9
0
def get_channels(region):
    return Session().get(M3U8_URL.format(region=region)).json()
Пример #10
0
 def new_session(self):
     self.logged_in = False
     self._session = Session(HEADERS, base_url=API_URL)
     self._set_authentication()
Пример #11
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()
Пример #12
0
 def new_session(self):
     self.logged_in = False
     self._session = Session(HEADERS, base_url=API_URL)
     self.set_access_token(userdata.get('access_token'))
Пример #13
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
Пример #14
0
def get_channels():
    return Session().get(M3U8_URL).json()
Пример #15
0
 def new_session(self):
     self.logged_in = False
     self._session = Session(HEADERS)
     self._set_authentication()
Пример #16
0
def epg(output, **kwargs):
    Session().chunked_dl(EPG_URL, output)
Пример #17
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()