Exemple #1
0
class ServerAPI():
    def __init__(self, ConfigFile):
        self._config = ConfigFile
        self._server = GooglePlayAPI(self._config.get_locale(),
                                     self._config.get_timezone())

    def login_with_token(self):
        self._server.login(None, None, self._config.get_gsfId(),
                           self._config.get_authSubToken())

    def get_token(self):
        self._server.login(self._config.get_mail(),
                           self._config.get_password())
        self._config.set_gsfId = self._server.gsfId
        self._config.set_authSubToken = self._server.authSubToken

    def download_app(self, appName):
        details = self._server.details(appName)
        docId = details.get('docId')
        filename = details.get('filename')
        if filename is None:
            filename = details.get('docId') + '.apk'
        if details is None:
            print('Package ', docid, ' does not exist on the server')
        else:
            print(docid, ' , ', filename, ' , ', details['versionCode'])
            data_gen = self._server.download(docid, details['versionCode'])
            data_gen = data_gen.get('file').get('data')
            filepath = filename
            with open(filepath, 'wb') as apk_file:
                for chunk in data_gen:
                    apk_file.write(chunk)
Exemple #2
0
def main():

    # get args
    sys.argv.pop(0)
    appNames = sys.argv

    # read token cache
    tokenCache = configparser.ConfigParser()
    tokenCache.read('.cache.ini')
    try:
        gsfId = int(tokenCache['DEFAULT']
                    ['gsfId'])  # does not get saved as int, but as str!
        authSubToken = tokenCache['DEFAULT']['authSubToken']
        timezone = tokenCache['DEFAULT']['timezone']
        locale = tokenCache['DEFAULT']['locale']
    except configparser.NoSectionError:
        print(
            "Missing login data. Please, check your cache file, or run login.py"
        )
        sys.exit(1)
    except configparser.ParsingError:
        print(
            "The cache file could not be read correctly. Please, check it, or run login.py"
        )
        sys.exit(1)
    except configparser.Error as e:
        print("Error ", e, " while reading cache file")
        sys.exit(1)

    server = GooglePlayAPI(locale, timezone)

    # log in with saved credentials
    try:
        server.login(None, None, gsfId, authSubToken)
    except:
        print("Error while trying to login to GP servers")
        sys.exit(2)

    for app in appNames:
        try:
            details = server.details(app)
            docid = details.get('docId')
            filename = details.get('filename')
            if filename is None:
                filename = details.get('docId') + '.apk'
            if details is None:
                print('Package ', docid, ' does not exist')
                continue
        except:
            print("Error while trying to get details for", app)
        else:
            print(docid, ' , ', filename, details['versionCode'])
            data_gen = server.download(docid, details['versionCode'])
            data_gen = data_gen.get('file').get('data')
            filepath = filename
            with open(filepath, 'wb') as apk_file:
                for chunk in data_gen:
                    apk_file.write(chunk)
Exemple #3
0
def main():

    # get args
    sys.argv.pop(0)
    searchQuery = ' '.join(sys.argv)

    # read token cache
    tokenCache = configparser.ConfigParser()
    tokenCache.read('.cache.ini')
    try:
        gsfId = int(tokenCache['DEFAULT']
                    ['gsfId'])  # does not get saved as int, but as str!
        authSubToken = tokenCache['DEFAULT']['authSubToken']
        timezone = tokenCache['DEFAULT']['timezone']
        locale = tokenCache['DEFAULT']['locale']
    except KeyError:
        print(
            "Missing login data. Please, check your cache file, or run login.py"
        )
        sys.exit(1)
    except configparser.ParsingError:
        print(
            "The cache file could not be read correctly. Please, check it, or run login.py"
        )
        sys.exit(1)
    except configparser.Error as e:
        print("Error ", e, " while reading cache file")
        sys.exit(1)

    server = GooglePlayAPI(locale, timezone)

    # log in with saved credentials
    try:
        server.login(None, None, gsfId, authSubToken)
    except:
        print("Error while trying to login to GP servers")
        sys.exit(2)

    resultRaw = server.search(searchQuery, 20)

    for app in resultRaw:
        docid = app.get('docId')
        details = server.details(docid)
        filename = app.get('filename')
        if filename is None:
            filename = details.get('docId') + '.apk'
        if details is None:
            print('Package ', docid, ' does not exist')
            continue
        print(docid, ' , ', filename, details['versionCode'])
Exemple #4
0
# BULK DETAILS

testApps = ['org.mozilla.firefox', 'com.non.existing.app']
bulk = server.bulkDetails(testApps)

print('\nTesting behaviour for non-existing apps\n')
if bulk[1] is not None:
    print('bulkDetails should return None for non-existing apps')
    sys.exit(1)

print('\nResult from bulkDetails for %s\n' % testApps[0])
print(bulk[0])

# DETAILS
print('\nGetting details for %s\n' % testApps[0])
details = server.details(testApps[0])
print(details)

# REVIEWS
print('\nGetting reviews for %s\n' % testApps[0])
revs = server.reviews(testApps[0])
for r in revs:
    print(r['comment'])

# BROWSE

print('\nBrowse play store categories\n')
browse = server.browse()
for b in browse:
    print(b['name'])
Exemple #5
0
class Play(object):
    def __init__(self, debug=True, fdroid=False):
        self.currentSet = []
        self.totalNumOfApps = 0
        self.debug = debug
        self.fdroid = fdroid
        self.firstRun = True
        self.loggedIn = False
        self._email = None
        self._passwd = None
        self._gsfId = None
        self._token = None
        self._last_fdroid_update = None

        # configuring download folder
        if self.fdroid:
            self.download_path = os.path.join(os.getcwd(), 'repo')
        else:
            self.download_path = os.getcwd()

        # configuring fdroid data
        if self.fdroid:
            self.fdroid_exe = 'fdroid'
            self.fdroid_path = os.getcwd()
            self.fdroid_init()

        # language settings
        locale = os.environ.get('LANG_LOCALE')
        if locale is None:
            locale = locale_service.getdefaultlocale()[0]
        timezone = os.environ.get('LANG_TIMEZONE')
        if timezone is None:
            timezone = 'Europe/Berlin'
        device = os.environ.get('DEVICE_CODE')
        if device is None:
            self.service = GooglePlayAPI(locale, timezone)
        else:
            self.service = GooglePlayAPI(locale,
                                         timezone,
                                         device_codename=device)

    def fdroid_init(self):
        found = False
        for path in os.environ['PATH'].split(':'):
            exe = os.path.join(path, self.fdroid_exe)
            if os.path.isfile(exe):
                found = True
                break
        if not found:
            print('Please install fdroid')
            sys.exit(1)
        elif os.path.isfile('config.py'):
            print('Repo already initalized, skipping init')
        else:
            p = Popen([self.fdroid_exe, 'init', '-v'],
                      stdout=PIPE,
                      stderr=PIPE)
            stdout, stderr = p.communicate()
            if p.returncode != 0:
                sys.stderr.write("error initializing fdroid repository " +
                                 stderr.decode('utf-8'))
                sys.exit(1)
        # backup config.py
        if self.debug:
            print('Checking config.py file')
        with open('config.py', 'r') as config_file:
            content = config_file.readlines()
        with open('config.py', 'w') as config_file:
            # copy all the original content of config.py
            # if the file was not modified with custom values, do it
            modified = False
            for line in content:
                if '# playmaker' in line:
                    modified = True
                config_file.write(line)
            if not modified:
                if self.debug:
                    print('Appending playmaker data to config.py')
                config_file.write(
                    '\n# playmaker\nrepo_name = "playmaker"\n'
                    'repo_description = "repository managed with '
                    'playmaker https://github.com/NoMore201/playmaker"\n')

        # ensure all folder and files are setup
        p = Popen([self.fdroid_exe, 'update', '--create-key', '-v'],
                  stdout=PIPE,
                  stderr=PIPE)
        stdout, stderr = p.communicate()
        if p.returncode != 0:
            print('Skipping fdroid update')
        else:
            print('Fdroid repo initialized successfully')

    def get_last_fdroid_update(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        return {'status': 'SUCCESS', 'message': str(self._last_fdroid_update)}

    def fdroid_update(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        if self.fdroid:
            try:
                p = Popen([self.fdroid_exe, 'update', '-c', '--clean'],
                          stdout=PIPE,
                          stderr=PIPE)
                stdout, stderr = p.communicate()
                if p.returncode != 0:
                    sys.stderr.write("error updating fdroid repository " +
                                     stderr.decode('utf-8'))
                    return makeError(FDROID_ERR)
                else:
                    print('Fdroid repo updated successfully')
                    self._last_fdroid_update = dt.today().replace(
                        microsecond=0)
                    return {'status': 'SUCCESS'}
            except Exception as e:
                return makeError(FDROID_ERR)
        else:
            return {'status': 'SUCCESS'}

    def get_apps(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}

        if self.firstRun:
            return {
                'status': 'PENDING',
                'total': self.totalNumOfApps,
                'current': len(self.currentSet)
            }
        return {
            'status': 'SUCCESS',
            'message': sorted(self.currentSet, key=lambda k: k['title'])
        }

    def set_encoded_credentials(self, email, password):
        self._email = base64.b64decode(email).decode('utf-8')
        self._passwd = base64.b64decode(password).decode('utf-8')

    def set_credentials(self, email, password):
        self._email = email
        self._passwd = password

    def set_token_credentials(self, gsfId, token):
        self._gsfId = int(gsfId, 16)
        self._token = token

    def has_credentials(self):
        passwd_credentials = self._email is not None and self._passwd is not None
        token_credentials = self._gsfId is not None and self._token is not None
        return passwd_credentials or token_credentials

    def login(self):
        if self.loggedIn:
            return {
                'status': 'SUCCESS',
                'securityCheck': False,
                'message': 'OK'
            }

        try:
            if not self.has_credentials():
                raise LoginError("missing credentials")
            self.service.login(self._email, self._passwd, self._gsfId,
                               self._token)
            self.loggedIn = True
            return {
                'status': 'SUCCESS',
                'securityCheck': False,
                'message': 'OK'
            }
        except LoginError as e:
            print('LoginError: {0}'.format(e))
            self.loggedIn = False
            return {
                'status': 'ERROR',
                'securityCheck': False,
                'message': 'Wrong credentials'
            }
        except SecurityCheckError as e:
            print('SecurityCheckError: {0}'.format(e))
            self.loggedIn = False
            return {
                'status': 'ERROR',
                'securityCheck': True,
                'message': 'Need security check'
            }
        except RequestError as e:
            # probably tokens are invalid, so it is better to
            # invalidate them
            print('RequestError: {0}'.format(e))
            self.loggedIn = False
            return {
                'status': 'ERROR',
                'securityCheck': False,
                'message': 'Request error, probably invalid token'
            }

    def update_state(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}

        print('Updating cache')
        with concurrent.futures.ProcessPoolExecutor() as executor:
            # get application ids from apk files
            apkFiles = [
                apk for apk in os.listdir(self.download_path)
                if os.path.splitext(apk)[1] == '.apk'
            ]
            self.totalNumOfApps = len(apkFiles)
            if self.totalNumOfApps != 0:
                future_to_app = [
                    executor.submit(get_details_from_apk, a,
                                    self.download_path, self.service)
                    for a in apkFiles
                ]
                for future in concurrent.futures.as_completed(future_to_app):
                    app = future.result()
                    if app is not None:
                        self.currentSet.append(app)
        print('Cache correctly initialized')
        self.firstRun = False

    def insert_app_into_state(self, newApp):
        found = False
        result = list(
            filter(lambda x: x['docid'] == newApp['docid'], self.currentSet))
        if len(result) > 0:
            found = True
            if self.debug:
                print('%s is already cached, updating..' % newApp['docid'])
                i = self.currentSet.index(result[0])
                self.currentSet[i] = newApp
        if not found:
            if self.debug:
                print('Adding %s into cache..' % newApp['docid'])
            self.currentSet.append(newApp)

    def search(self, appName, numItems=15):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}

        try:
            apps = self.service.search(appName)
        except RequestError as e:
            print(e)
            self.loggedIn = False
            return {'status': 'ERROR', 'message': SESSION_EXPIRED_ERR}
        except LoginError as e:
            print(SESSION_EXPIRED_ERR)
            self.loggedIn = False
        except IndexError as e:
            print(SESSION_EXPIRED_ERR)
            self.loggedIn = False

        return {'status': 'SUCCESS', 'message': apps}

    def details(self, app):
        try:
            details = self.service.details(app)
        except RequestError:
            details = None
        return details

    def get_bulk_details(self, apksList):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        try:
            apps = [self.details(a) for a in apksList]
        except LoginError as e:
            print(e)
            self.loggedIn = False
        return apps

    def download_selection(self, apps):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        success = []
        failed = []
        unavail = []

        for app in apps:
            docid = app.get('docid')
            details = self.details(docid)
            filename = app.get('filename')
            if filename is None:
                filename = details.get('docid') + '.apk'
            if details is None:
                print('Package %s does not exits' % docid)
                unavail.append(docid)
                continue
            print('Downloading %s' % docid)
            try:
                if details.get('offer')[0].get('micros') == 0:
                    data_gen = self.service.download(
                        docid,
                        details.get('details').get('appDetails')
                        ['versionCode'])
                else:
                    data_gen = self.service.delivery(
                        docid,
                        details.get('details').get('appDetails')
                        ['versionCode'])
                data_gen = data_gen.get('file').get('data')
            except IndexError as exc:
                print(exc)
                print('Package %s does not exists' % docid)
                unavail.append(docid)
            except Exception as exc:
                print(exc)
                print('Failed to download %s' % docid)
                failed.append(docid)
            else:
                filepath = os.path.join(self.download_path, filename)
                try:
                    with open(filepath, 'wb') as apk_file:
                        for chunk in data_gen:
                            apk_file.write(chunk)
                except IOError as exc:
                    print('Error while writing %s: %s' % (filename, exc))
                    failed.append(docid)
                details['filename'] = filename
                success.append(details)
        for x in success:
            self.insert_app_into_state(x)
        return {
            'status': 'SUCCESS',
            'message': {
                'success': success,
                'failed': failed,
                'unavail': unavail
            }
        }

    def check_local_apks(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        if len(self.currentSet) == 0:
            print('There is no package')
            return {'status': 'SUCCESS', 'message': []}
        else:
            toUpdate = []
            for app in self.currentSet:
                details = self.details(app.get('docid'))
                #print(details)
                if details is None:
                    print('%s not available in Play Store' % app['docid'])
                    continue
                details['filename'] = app.get('filename')
                if self.debug:
                    print('Checking %s' % app['docid'])
                    print('%d == %d ?' %
                          (app.get('details').get('appDetails')['versionCode'],
                           details.get('details').get('appDetails')
                           ['versionCode']))
                if app.get('details').get(
                        'appDetails')['versionCode'] != details.get(
                            'details').get('appDetails')['versionCode']:
                    toUpdate.append(details)
        return {'status': 'SUCCESS', 'message': toUpdate}

    def remove_local_app(self, docid):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        # get app from cache
        app = list(filter(lambda x: x['docid'] == docid, self.currentSet))
        if len(app) < 1:
            return {'status': 'ERROR'}
        apkPath = os.path.join(self.download_path, app[0]['filename'])
        if os.path.isfile(apkPath):
            os.remove(apkPath)
            self.currentSet.remove(app[0])
            return {'status': 'SUCCESS'}
        return {'status': 'ERROR'}
Exemple #6
0
# BULK DETAILS
testApps = ['org.mozilla.focus', 'com.non.existing.app']
bulk = server.bulkDetails(testApps)

print('\nTesting behaviour for non-existing apps\n')
if bulk[1] is not None:
    print('bulkDetails should return None for non-existing apps')
    sys.exit(1)

print('\nResult from bulkDetails for %s\n' % testApps[0])
print(bulk[0])

# DETAILS
print('\nGetting details for %s\n' % testApps[0])
details = server.details(testApps[0])
print(details)

# REVIEWS
print('\nGetting reviews for %s\n' % testApps[0])
revs = server.reviews(testApps[0])
for r in revs:
    print(r['comment'])

# BROWSE

print('\nBrowse play store categories\n')
browse = server.browse()
for b in browse:
    print(b['name'])
Exemple #7
0
class Play(object):
    def __init__(self, debug=True, fdroid=False):
        self.currentSet = []
        self.totalNumOfApps = 0
        self.debug = debug
        self.fdroid = fdroid
        self.firstRun = True
        self.loggedIn = False
        self._email = None
        self._passwd = None
        self._last_fdroid_update = None

        # configuring download folder
        if self.fdroid:
            self.download_path = os.path.join(os.getcwd(), 'repo')
        else:
            self.download_path = os.getcwd()

        # configuring fdroid data
        if self.fdroid:
            self.fdroid_exe = 'fdroid'
            self.fdroid_path = os.getcwd()
            self.fdroid_init()

        self.service = GooglePlayAPI(self.debug)

    def fdroid_init(self):
        found = False
        for path in os.environ['PATH'].split(':'):
            exe = os.path.join(path, self.fdroid_exe)
            if os.path.isfile(exe):
                found = True
                break
        if not found:
            print('Please install fdroid')
            sys.exit(1)
        elif os.path.isfile('./config.py'):
            print('Repo already initalized, skipping')
        else:
            p = Popen([self.fdroid_exe, 'init', '-v'],
                      stdout=PIPE,
                      stderr=PIPE)
            stdout, stderr = p.communicate()
            if p.returncode != 0:
                sys.stderr.write("error initializing fdroid repository " +
                                 stderr.decode('utf-8'))
                sys.exit(1)
        # backup config.py
        if self.debug:
            print('Backing up config.py')
        move('./config.py', './config-backup.py')
        with open('./config-backup.py') as f1:
            content = f1.readlines()
        # copy all content of backup in the main config.py
        # if the file was not modified with custom values, do it
        with open('./config.py', 'w') as f:
            modified = False
            for line in content:
                if '# playmaker' in line:
                    modified = True
                f.write(line)
            if not modified:
                if self.debug:
                    print('Appending playmaker data to config.py')
                f.write('\n# playmaker\nrepo_name = "playmaker"\n'
                        'repo_description = "repository managed with '
                        'playmaker https://github.com/NoMore201/playmaker"\n')
        os.chmod('./config.py', 0o600)

        # ensure all folder and files are setup
        p = Popen([self.fdroid_exe, 'update', '--create-key', '-v'],
                  stdout=PIPE,
                  stderr=PIPE)
        stdout, stderr = p.communicate()
        if p.returncode != 0:
            sys.stderr.write("error initializing fdroid repository " +
                             stderr.decode('utf-8'))
        else:
            print('Fdroid repo initialized successfully')

    def get_last_fdroid_update(self):
        return {'status': 'SUCCESS', 'message': str(self._last_fdroid_update)}

    def fdroid_update(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        if self.fdroid:
            try:
                p = Popen([self.fdroid_exe, 'update', '-c', '--clean'],
                          stdout=PIPE,
                          stderr=PIPE)
                stdout, stderr = p.communicate()
                if p.returncode != 0:
                    sys.stderr.write("error updating fdroid repository " +
                                     stderr.decode('utf-8'))
                    return makeError(FDROID_ERR)
                else:
                    print('Fdroid repo updated successfully')
                    self._last_fdroid_update = dt.today().replace(
                        microsecond=0)
                    return {'status': 'SUCCESS'}
            except Exception as e:
                return makeError(FDROID_ERR)
        else:
            return {'status': 'SUCCESS'}

    def get_apps(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        if self.firstRun:
            return {
                'status': 'PENDING',
                'total': self.totalNumOfApps,
                'current': len(self.currentSet)
            }
        return {
            'status': 'SUCCESS',
            'message': sorted(self.currentSet, key=lambda k: k['title'])
        }

    def login(self, email=None, password=None):
        def unpad(s):
            return s[:-ord(s[len(s) - 1:])]

        try:
            if email is not None and password is not None:
                self._email = base64.b64decode(email).decode('utf-8')
                self._passwd = base64.b64decode(password).decode('utf-8')
                self.service.login(self._email, self._passwd, None, None)
            else:
                # otherwise we need only to refresh auth token
                encrypted = self.service.encrypt_password(
                    self._email, self._passwd).decode('utf-8')
                self.service.getAuthSubToken(self._email, encrypted)
            self.loggedIn = True
            return {'status': 'SUCCESS', 'message': 'OK'}
        except LoginError as e:
            print('Wrong credentials: {0}'.format(e))
            return {'status': 'ERROR', 'message': 'Wrong credentials'}
        except RequestError as e:
            # probably tokens are invalid, so it is better to
            # invalidate them
            print(e)
            return {
                'status': 'ERROR',
                'message': 'Request error, probably invalid token'
            }

    def update_state(self):
        print('Updating cache')
        with concurrent.futures.ProcessPoolExecutor() as executor:
            # get application ids from apk files
            apkFiles = [
                apk for apk in os.listdir(self.download_path)
                if os.path.splitext(apk)[1] == '.apk'
            ]
            self.totalNumOfApps = len(apkFiles)
            if self.totalNumOfApps != 0:
                future_to_app = [
                    executor.submit(get_details_from_apk, a,
                                    self.download_path, self.service)
                    for a in apkFiles
                ]
                for future in concurrent.futures.as_completed(future_to_app):
                    app = future.result()
                    if app is not None:
                        self.currentSet.append(app)
        print('Cache correctly initialized')
        self.firstRun = False

    def insert_app_into_state(self, newApp):
        found = False
        result = list(
            filter(lambda x: x['docId'] == newApp['docId'], self.currentSet))
        if len(result) > 0:
            found = True
            if self.debug:
                print('%s is already cached, updating..' % newApp['docId'])
                i = self.currentSet.index(result[0])
                self.currentSet[i] = newApp
        if not found:
            if self.debug:
                print('Adding %s into cache..' % newApp['docId'])
            self.currentSet.append(newApp)

    def search(self, appName, numItems=15):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        try:
            apps = self.service.search(appName, numItems, None)
        except RequestError as e:
            print(e)
            self.loggedIn = False
            return {'status': 'ERROR', 'message': SESSION_EXPIRED_ERR}
        except LoginError as e:
            print(SESSION_EXPIRED_ERR)
            self.loggedIn = False
        except IndexError as e:
            print(SESSION_EXPIRED_ERR)
            self.loggedIn = False

        return {'status': 'SUCCESS', 'message': apps}

    def details(self, app):
        try:
            details = self.service.details(app)
        except RequestError:
            details = None
        return details

    def get_bulk_details(self, apksList):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        try:
            apps = [self.details(a) for a in apksList]
        except LoginError as e:
            print(e)
            self.loggedIn = False
        return apps

    def download_selection(self, appNames):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        success = []
        failed = []
        unavail = []

        for app in appNames:
            details = self.details(app)
            if details is None:
                print('Package %s does not exits' % app)
                unavail.append(app)
                continue
            print('Downloading %s' % app)
            try:
                if details['offer'][0]['formattedAmount'] == 'Free':
                    data = self.service.download(app, details['versionCode'])
                else:
                    data = self.service.delivery(app, details['versionCode'])
            except IndexError as exc:
                print(exc)
                print('Package %s does not exists' % app)
                unavail.append(app)
            except Exception as exc:
                print(exc)
                print('Failed to download %s' % app)
                failed.append(app)
            else:
                filename = app + '.apk'
                filepath = os.path.join(self.download_path, filename)
                try:
                    open(filepath, 'wb').write(data['data'])
                except IOError as exc:
                    print('Error while writing %s: %s' % (filename, exc))
                    failed.append(app)
                details['filename'] = filename
                success.append(details)
        for x in success:
            self.insert_app_into_state(x)
        return {
            'status': 'SUCCESS',
            'message': {
                'success': success,
                'failed': failed,
                'unavail': unavail
            }
        }

    def check_local_apks(self):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        if len(self.currentSet) == 0:
            print('There is no package')
            return {'status': 'SUCCESS', 'message': []}
        else:
            toUpdate = []
            for app in self.currentSet:
                details = self.details(app['docId'])
                if details is None:
                    print('%s not available in Play Store' % app['docId'])
                    continue
                if self.debug:
                    print('Checking %s' % app['docId'])
                    print('%d == %d ?' %
                          (app['versionCode'], details['versionCode']))
                if app['versionCode'] != details['versionCode']:
                    toUpdate.append(details['docId'])
        return {'status': 'SUCCESS', 'message': toUpdate}

    def remove_local_app(self, docId):
        if not self.loggedIn:
            return {'status': 'UNAUTHORIZED'}
        # get app from cache
        app = list(filter(lambda x: x['docId'] == docId, self.currentSet))
        if len(app) < 1:
            return {'status': 'ERROR'}
        apkPath = os.path.join(self.download_path, app[0]['filename'])
        if os.path.isfile(apkPath):
            os.remove(apkPath)
            self.currentSet.remove(app[0])
            return {'status': 'SUCCESS'}
        return {'status': 'ERROR'}
Exemple #8
0
                               device_codename=args.devicecode)
        server.login(email, password, None, None)
        gsfId = str(server.gsfId)
        authSubToken = server.authSubToken

        if not config.has_section(CONFIG_SECTION):
            config.add_section(CONFIG_SECTION)
        # write fetched values to config
        config.set(CONFIG_SECTION, CONFIG_GSFID, gsfId)
        config.set(CONFIG_SECTION, CONFIG_AUTHSUBTOKEN, str(authSubToken))

        config.write(configfile)

server = GooglePlayAPI(SERVER_LOCALE,
                       SERVER_TZ,
                       device_codename=args.devicecode)
server.login(None, None, int(gsfId), authSubToken)

app = server.details(args.package)
docid = app['docId']
ver = app["versionString"]
filename = docid + "-" + ver + ".apk"
print("Fetching docId", docid, "to file", filename)
#print(app)

fl = server.download(docid)
with open(filename, 'wb') as apk_file:
    for chunk in fl.get('file').get('data'):
        apk_file.write(chunk)
    print('\nDownload successful\n')
Exemple #9
0
    device_log_ins = json.load(logins)
    current_log_in = device_log_ins['pixel_2']  # Change this to change device

server = GooglePlayAPI("en_US", "America/Toronto",
                       current_log_in['deviceName'])

print("Logging in...")
server.login(gsfId=current_log_in['gsfId'],
             authSubToken=current_log_in['authSubToken'])
print("Complete!")

# Replace these with your package and version code names
docid = "com.package.name"
versionCode = 1234

details = server.details(docid, versionCode)
title = details['title'].replace("\n", "-")

print(f"""App Details Below:

Name: {title}
Package: {details['docid']}
Version Code: {details['details']['appDetails']['versionCode']}
App Version: {details['details']['appDetails']['versionString']}
""")

print("Attempting to download {}".format(docid))
fl = server.download(docid, versionCode=versionCode)
with open(f"{docid}.apk", "wb") as apk_file:
    parts = int(fl['file']['total_size']) / fl['file']['chunk_size']
    for index, chunk in enumerate(fl.get("file").get("data")):
class GPlaycli(object):
    def __init__(self, args=None, credentials=None):
        # no config file given, look for one
        if credentials is None:
            # default local user configs
            cred_paths_list = [
                'gplaycli.conf',
                os.path.expanduser("~") + '/.config/gplaycli/gplaycli.conf',
                '/etc/gplaycli/gplaycli.conf'
            ]
            tmp_list = list(cred_paths_list)
            while not os.path.isfile(tmp_list[0]):
                tmp_list.pop(0)
                if not tmp_list:
                    raise OSError("No configuration file found at %s" % cred_paths_list)
            credentials = tmp_list[0]

        default_values = dict()
        self.configparser = configparser.ConfigParser(default_values)
        self.configparser.read(credentials)
        self.config = {key: value for key, value in self.configparser.items("Credentials")}

        self.tokencachefile = os.path.expanduser(self.configparser.get("Cache", "token"))
        self.playstore_api = None

        # default settings, ie for API calls
        if args is None:
            self.yes = True
            self.verbose = True
            self.progress_bar = True
            self.device_codename = 'bacon'
            self.addfiles_enable = False
            self.token_enable = self.configparser.getboolean('Credentials', 'token')
            self.token_url = self.configparser.get('Credentials', 'token_url')
            self.token, self.gsfid = self.retrieve_token()

        # if args are passed
        else:
            self.yes = args.yes_to_all
            self.verbose = args.verbose
            self.progress_bar = args.progress_bar
            self.set_download_folder(args.update_folder)
            self.device_codename = args.device_codename
            self.addfiles_enable = args.addfiles_enable
            if args.token_enable is None:
                self.token_enable = self.configparser.getboolean('Credentials', 'token')
            else:
                self.token_enable = args.token_enable
            if self.token_enable:
                if args.token_url is None:
                    self.token_url = self.configparser.get('Credentials', 'token_url')
                else:
                    self.token_url = args.token_url
                self.token, self.gsfid = self.retrieve_token()

    def get_cached_token(self):
        try:
            with open(self.tokencachefile, 'r') as tcf:
                token, gsfid = tcf.readline().split()
                if not token:
                    token = None
                    gsfid = None
        except (IOError, ValueError):  # cache file does not exists or is corrupted
            token = None
            gsfid = None
        return token, gsfid

    def write_cached_token(self, token, gsfid):
        try:
            # creates cachedir if not exists
            cachedir = os.path.dirname(self.tokencachefile)
            if not os.path.exists(cachedir):
                os.mkdir(cachedir)
            with open(self.tokencachefile, 'w') as tcf:
                tcf.write("%s %s" % (token, gsfid))
        except IOError as e:
            raise IOError("Failed to write token to cache file: %s %s" % (self.tokencachefile, e.strerror))

    def retrieve_token(self, force_new=False):
        token, gsfid = self.get_cached_token()
        if token is not None and not force_new:
            return token, gsfid
        r = requests.get(self.token_url)
        if r.text == 'Auth error':
            print('Token dispenser auth error, probably too many connections')
            sys.exit(ERRORS.TOKEN_DISPENSER_AUTH_ERROR)
        elif r.text == "Server error":
            print('Token dispenser server error')
            sys.exit(ERRORS.TOKEN_DISPENSER_SERVER_ERROR)
        token, gsfid = r.text.split(" ")
        self.token = token
        self.gsfid = gsfid
        self.write_cached_token(token, gsfid)
        return token, gsfid

    def set_download_folder(self, folder):
        self.config["download_folder_path"] = folder

    def connect_to_googleplay_api(self):
        self.playstore_api = GooglePlayAPI(device_codename=self.device_codename)
        error = None
        email = None
        password = None
        authSubToken = None
        gsfId = None
        if self.token_enable is False:
            email = self.config["gmail_address"]
            if self.config["gmail_password"]:
                password = self.config["gmail_password"]
            elif self.config["keyring_service"] and HAVE_KEYRING is True:
                password = keyring.get_password(self.config["keyring_service"], email)
            elif self.config["keyring_service"] and HAVE_KEYRING is False:
                print("You asked for keyring service but keyring package is not installed")
                sys.exit(ERRORS.KEYRING_NOT_INSTALLED)
        else:
            authSubToken = self.token
            gsfId = int(self.gsfid, 16)
        try:
            self.playstore_api.login(email=email,
                                     password=password,
                                     authSubToken=authSubToken,
                                     gsfId=gsfId)
        except (ValueError, IndexError, LoginError) as ve:  # invalid token or expired
            self.retrieve_token(force_new=True)
            self.playstore_api.login(authSubToken=self.token, gsfId=int(self.gsfid, 16))
        success = True
        return success, error

    def list_folder_apks(self, folder):
        list_of_apks = [filename for filename in os.listdir(folder) if filename.endswith(".apk")]
        return list_of_apks

    def prepare_analyse_apks(self):
        download_folder_path = self.config["download_folder_path"]
        list_of_apks = [filename for filename in os.listdir(download_folder_path) if
                        os.path.splitext(filename)[1] == ".apk"]
        if list_of_apks:
            self.analyse_local_apks(list_of_apks, self.playstore_api, download_folder_path,
                                    self.prepare_download_updates)

    def analyse_local_apks(self, list_of_apks, playstore_api, download_folder_path, return_function):
        list_apks_to_update = []
        package_bunch = []
        version_codes = []
        for position, filename in enumerate(list_of_apks):
            filepath = os.path.join(download_folder_path, filename)
            a = APK(filepath)
            packagename = a.package
            package_bunch.append(packagename)
            version_codes.append(a.version_code)

        # BulkDetails requires only one HTTP request
        # Get APK info from store
        details = playstore_api.bulkDetails(package_bunch)
        for detail, packagename, apk_version_code in zip(details, package_bunch, version_codes):
            store_version_code = detail['versionCode']

            # Compare
            if apk_version_code != "" and int(apk_version_code) < int(store_version_code) and int(
                    store_version_code) != 0:
                # Add to the download list
                list_apks_to_update.append([packagename, filename, int(apk_version_code), int(store_version_code)])

        return_function(list_apks_to_update)

    def prepare_download_updates(self, list_apks_to_update):
        if list_apks_to_update:
            list_of_packages_to_download = []

            # Ask confirmation before downloading
            message = "The following applications will be updated :"
            for packagename, filename, apk_version_code, store_version_code in list_apks_to_update:
                message += "\n%s Version : %s -> %s" % (filename, apk_version_code, store_version_code)
                list_of_packages_to_download.append([packagename, filename])
            message += "\n"
            print(message)
            if not self.yes:
                print("\nDo you agree?")
                return_value = input('y/n ?')

            if self.yes or return_value == 'y':
                downloaded_packages = self.download_selection(self.playstore_api, list_of_packages_to_download,
                                                              self.after_download)
                return_string = str()
                for package in downloaded_packages:
                    return_string += package + " "
                print("Updated: " + return_string[:-1])
        else:
            print("Everything is up to date !")
            sys.exit(ERRORS.OK)

    def download_selection(self, playstore_api, list_of_packages_to_download, return_function):
        success_downloads = list()
        failed_downloads = list()
        unavail_downloads = list()

        # BulkDetails requires only one HTTP request
        # Get APK info from store
        details = playstore_api.bulkDetails([pkg[0] for pkg in list_of_packages_to_download])
        position = 1
        for detail, item in zip(details, list_of_packages_to_download):
            packagename, filename = item

            # Check for download folder
            download_folder_path = self.config["download_folder_path"]
            if not os.path.isdir(download_folder_path):
                os.mkdir(download_folder_path)

            # Get the version code and the offer type from the app details
            # m = playstore_api.details(packagename)
            vc = detail['versionCode']

            # Download
            try:
                data_dict = playstore_api.download(packagename, vc, progress_bar=self.progress_bar, expansion_files=self.addfiles_enable)
                success_downloads.append(packagename)
            except IndexError as exc:
                print("Error while downloading %s : %s" % (packagename,
                                                           "this package does not exist, "
                                                           "try to search it via --search before"))
                unavail_downloads.append((item, exc))
            except Exception as exc:
                print("Error while downloading %s : %s" % (packagename, exc))
                failed_downloads.append((item, exc))
            else:
                if filename is None:
                    filename = packagename + ".apk"
                filepath = os.path.join(download_folder_path, filename)

                data = data_dict['data']
                additional_data = data_dict['additionalData']

                try:
                    open(filepath, "wb").write(data)
                    if additional_data:
                        for obb_file in additional_data:
                            obb_filename = "%s.%s.%s.obb" % (obb_file["type"], obb_file["versionCode"], data_dict["docId"])
                            obb_filename = os.path.join(download_folder_path, obb_filename)
                            open(obb_filename, "wb").write(obb_file["data"])
                except IOError as exc:
                    print("Error while writing %s : %s" % (packagename, exc))
                    failed_downloads.append((item, exc))
            position += 1

        success_items = set(success_downloads)
        failed_items = set([item[0] for item, error in failed_downloads])
        unavail_items = set([item[0] for item, error in unavail_downloads])
        to_download_items = set([item[0] for item in list_of_packages_to_download])

        return_function(failed_downloads + unavail_downloads)
        return to_download_items - failed_items

    @staticmethod
    def after_download(failed_downloads):
        # Info message
        if not failed_downloads:
            message = "Download complete"
        else:
            message = "A few packages could not be downloaded :"
            for item, exception in failed_downloads:
                package_name, filename = item
                if filename is not None:
                    message += "\n%s : %s" % (filename, package_name)
                else:
                    message += "\n%s" % package_name
                message += "\n%s\n" % exception

        print(message)

    def raw_search(self, results_list, search_string, nb_results):
        # Query results
        return self.playstore_api.search(search_string, nb_result=nb_results)

    def search(self, results_list, search_string, nb_results, free_only=True, include_headers=True):
        try:
            results = self.raw_search(results_list, search_string, nb_results)
        except IndexError:
            results = list()
        if not results:
            print("No result")
            return
        all_results = list()
        if include_headers:
            # Name of the columns
            col_names = ["Title", "Creator", "Size", "Downloads", "Last Update", "AppID", "Version", "Rating"]
            all_results.append(col_names)
        # Compute results values
        for result in results:
            if free_only and result['offer'][0]['checkoutFlowRequired']:  # if not Free to download
                continue
            l = [result['title'],
                 result['author'],
                 util.sizeof_fmt(result['installationSize']),
                 result['numDownloads'],
                 result['uploadDate'],
                 result['docId'],
                 result['versionCode'],
                 "%.2f" % result["aggregateRating"]["starRating"]
                ]
            if len(all_results) < int(nb_results) + 1:
                all_results.append(l)

        if self.verbose:
            # Print a nice table
            col_width = list()
            for column_indice in range(len(all_results[0])):
                col_length = max([len("%s" % row[column_indice]) for row in all_results])
                col_width.append(col_length + 2)

            for result in all_results:
                print("".join(str("%s" % item).strip().ljust(col_width[indice]) for indice, item in
                              enumerate(result)))
        return all_results

    def download_packages(self, list_of_packages_to_download):
        self.download_selection(self.playstore_api, [(pkg, None) for pkg in list_of_packages_to_download],
                                self.after_download)

    def get_package_info(self, package):
        return self.playstore_api.details(package)

    def write_logfiles(self, success, failed, unavail):
        for result, logfile in [(success, self.success_logfile),
                                (failed, self.failed_logfile),
                                (unavail, self.unavail_logfile)
                               ]:
            if result:
                with open(logfile, 'w') as _buffer:
                    for package in result:
                        print(package, file=_buffer)
Exemple #11
0
                      db="playstore_apps_db")
mycursor = con.cursor()
mycursor.execute("""

                SELECT app_url FROM apps_urls WHERE id=35

                """)
res = mycursor.fetchall()

for row in res:
    # print(type(row))
    mypackageName = ''.join(row)

    print(mypackageName)

    details = server.details(mypackageName)

    app_playstore_id = details['docid']
    app_playstore_id = ''.join(app_playstore_id)
    print("PlayStoreID: ", app_playstore_id)
    print(" ")

    App_name = details['title']
    App_name = ''.join(App_name)
    print("Application Name : ", App_name)
    print(" ")

    if 'creator' in details:
        developer_name = details['creator']
        developer_name = ''.join(developer_name)
        print("Developer Name : ", developer_name)
Exemple #12
0
from gpapi.googleplay import GooglePlayAPI, RequestError
import json

server = GooglePlayAPI(debug=True, locale='id-ID')
server.login(
    None, None, int('3d9dadcd34b1d5bf', 16),
    'vAVzTIwkcGaYMqtXiOLtk-ty7Jwj5IltXs4o23oPDO3g5GPidel9ktzaVwPnZnQVX-n3eA.')

details = server.details('com.snapchat.android')
print(json.dumps(details, sort_keys=True, indent=4))