mirror of
https://github.com/FliegendeWurst/googleplay-api.git
synced 2024-11-22 12:54:58 +00:00
parent
2ab7ce09c6
commit
9d0d14450b
126
gpapi/config.py
126
gpapi/config.py
@ -19,20 +19,14 @@ GOOGLE_PUBKEY = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdo
|
|||||||
# if you want to add another phone, just create another section in
|
# if you want to add another phone, just create another section in
|
||||||
# the file. Some configurations for common phones can be found here:
|
# the file. Some configurations for common phones can be found here:
|
||||||
# https://github.com/yeriomin/play-store-api/tree/master/src/main/resources
|
# https://github.com/yeriomin/play-store-api/tree/master/src/main/resources
|
||||||
|
filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
||||||
|
'device.properties')
|
||||||
|
|
||||||
if VERSION == 2:
|
if VERSION == 2:
|
||||||
config = ConfigParser.ConfigParser()
|
config = ConfigParser.ConfigParser()
|
||||||
else:
|
else:
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
|
||||||
'device.properties')
|
|
||||||
config.read(filepath)
|
config.read(filepath)
|
||||||
device = {}
|
|
||||||
# initialize device, because we need to setup UserAgent
|
|
||||||
# before the end of login method. If the login defines a different
|
|
||||||
# device, it won't cause conflicts
|
|
||||||
for (key, value) in config.items('angler'):
|
|
||||||
device[key] = value
|
|
||||||
|
|
||||||
|
|
||||||
def getDevicesCodenames():
|
def getDevicesCodenames():
|
||||||
@ -50,40 +44,58 @@ def getDevicesReadableNames():
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def getUserAgent():
|
class DeviceBuilder(object):
|
||||||
|
|
||||||
|
def __init__(self, device):
|
||||||
|
self.device = {}
|
||||||
|
for (key, value) in config.items(device):
|
||||||
|
self.device[key] = value
|
||||||
|
|
||||||
|
def getUserAgent(self):
|
||||||
return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 ("
|
return ("Android-Finsky/8.1.72.S-all [6] [PR] 165478484 ("
|
||||||
"api=3"
|
"api=3"
|
||||||
",versionCode={versionCode}"
|
",versionCode={versionCode}"
|
||||||
",sdk={sdk}"
|
",sdk={sdk}"
|
||||||
",device={device}"
|
",device={device}"
|
||||||
",hardware={hardware}"
|
",hardware={hardware}"
|
||||||
",product={product}").format(versionCode=device['vending.version'],
|
",product={product}"
|
||||||
sdk=device['build.version.sdk_int'],
|
"").format(versionCode=self.device['vending.version'],
|
||||||
device=device['build.device'],
|
sdk=self.device['build.version.sdk_int'],
|
||||||
hardware=device['build.hardware'],
|
device=self.device['build.device'],
|
||||||
product=device['build.product'])
|
hardware=self.device['build.hardware'],
|
||||||
|
product=self.device['build.product'])
|
||||||
|
|
||||||
|
def getAndroidCheckinRequest(self):
|
||||||
|
request = googleplay_pb2.AndroidCheckinRequest()
|
||||||
|
request.id = 0
|
||||||
|
request.checkin.CopyFrom(self.getAndroidCheckin())
|
||||||
|
request.locale = LANG
|
||||||
|
request.timeZone = TIMEZONE
|
||||||
|
request.version = 3
|
||||||
|
request.deviceConfiguration.CopyFrom(self.getDeviceConfig())
|
||||||
|
request.fragment = 0
|
||||||
|
return request
|
||||||
|
|
||||||
def getDeviceConfig():
|
def getDeviceConfig(self):
|
||||||
libList = device['sharedlibraries'].split(",")
|
libList = self.device['sharedlibraries'].split(",")
|
||||||
featureList = device['features'].split(",")
|
featureList = self.device['features'].split(",")
|
||||||
localeList = device['locales'].split(",")
|
localeList = self.device['locales'].split(",")
|
||||||
glList = device['gl.extensions'].split(",")
|
glList = self.device['gl.extensions'].split(",")
|
||||||
platforms = device['platforms'].split(",")
|
platforms = self.device['platforms'].split(",")
|
||||||
|
|
||||||
hasFiveWayNavigation = (device['hasfivewaynavigation'] == 'true')
|
hasFiveWayNavigation = (self.device['hasfivewaynavigation'] == 'true')
|
||||||
hasHardKeyboard = (device['hashardkeyboard'] == 'true')
|
hasHardKeyboard = (self.device['hashardkeyboard'] == 'true')
|
||||||
deviceConfig = googleplay_pb2.DeviceConfigurationProto()
|
deviceConfig = googleplay_pb2.DeviceConfigurationProto()
|
||||||
deviceConfig.touchScreen = int(device['touchscreen'])
|
deviceConfig.touchScreen = int(self.device['touchscreen'])
|
||||||
deviceConfig.keyboard = int(device['keyboard'])
|
deviceConfig.keyboard = int(self.device['keyboard'])
|
||||||
deviceConfig.navigation = int(device['navigation'])
|
deviceConfig.navigation = int(self.device['navigation'])
|
||||||
deviceConfig.screenLayout = int(device['screenlayout'])
|
deviceConfig.screenLayout = int(self.device['screenlayout'])
|
||||||
deviceConfig.hasHardKeyboard = hasHardKeyboard
|
deviceConfig.hasHardKeyboard = hasHardKeyboard
|
||||||
deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation
|
deviceConfig.hasFiveWayNavigation = hasFiveWayNavigation
|
||||||
deviceConfig.screenDensity = int(device['screen.density'])
|
deviceConfig.screenDensity = int(self.device['screen.density'])
|
||||||
deviceConfig.screenWidth = int(device['screen.width'])
|
deviceConfig.screenWidth = int(self.device['screen.width'])
|
||||||
deviceConfig.screenHeight = int(device['screen.height'])
|
deviceConfig.screenHeight = int(self.device['screen.height'])
|
||||||
deviceConfig.glEsVersion = int(device['gl.version'])
|
deviceConfig.glEsVersion = int(self.device['gl.version'])
|
||||||
for x in platforms:
|
for x in platforms:
|
||||||
deviceConfig.nativePlatform.append(x)
|
deviceConfig.nativePlatform.append(x)
|
||||||
for x in libList:
|
for x in libList:
|
||||||
@ -96,46 +108,30 @@ def getDeviceConfig():
|
|||||||
deviceConfig.glExtension.append(x)
|
deviceConfig.glExtension.append(x)
|
||||||
return deviceConfig
|
return deviceConfig
|
||||||
|
|
||||||
|
def getAndroidBuild(self):
|
||||||
def getAndroidBuild():
|
|
||||||
androidBuild = googleplay_pb2.AndroidBuildProto()
|
androidBuild = googleplay_pb2.AndroidBuildProto()
|
||||||
androidBuild.id = device['build.fingerprint']
|
androidBuild.id = self.device['build.fingerprint']
|
||||||
androidBuild.product = device['build.hardware']
|
androidBuild.product = self.device['build.hardware']
|
||||||
androidBuild.carrier = device['build.brand']
|
androidBuild.carrier = self.device['build.brand']
|
||||||
androidBuild.radio = device['build.radio']
|
androidBuild.radio = self.device['build.radio']
|
||||||
androidBuild.bootloader = device['build.bootloader']
|
androidBuild.bootloader = self.device['build.bootloader']
|
||||||
androidBuild.device = device['build.device']
|
androidBuild.device = self.device['build.device']
|
||||||
androidBuild.sdkVersion = int(device['build.version.sdk_int'])
|
androidBuild.sdkVersion = int(self.device['build.version.sdk_int'])
|
||||||
androidBuild.model = device['build.model']
|
androidBuild.model = self.device['build.model']
|
||||||
androidBuild.manufacturer = device['build.manufacturer']
|
androidBuild.manufacturer = self.device['build.manufacturer']
|
||||||
androidBuild.buildProduct = device['build.product']
|
androidBuild.buildProduct = self.device['build.product']
|
||||||
androidBuild.client = device['client']
|
androidBuild.client = self.device['client']
|
||||||
androidBuild.otaInstalled = False
|
androidBuild.otaInstalled = False
|
||||||
androidBuild.timestamp = int(time.time())
|
androidBuild.timestamp = int(time.time())
|
||||||
androidBuild.googleServices = int(device['gsf.version'])
|
androidBuild.googleServices = int(self.device['gsf.version'])
|
||||||
return androidBuild
|
return androidBuild
|
||||||
|
|
||||||
|
def getAndroidCheckin(self):
|
||||||
def getAndroidCheckin():
|
|
||||||
androidCheckin = googleplay_pb2.AndroidCheckinProto()
|
androidCheckin = googleplay_pb2.AndroidCheckinProto()
|
||||||
androidCheckin.build.CopyFrom(getAndroidBuild())
|
androidCheckin.build.CopyFrom(self.getAndroidBuild())
|
||||||
androidCheckin.lastCheckinMsec = 0
|
androidCheckin.lastCheckinMsec = 0
|
||||||
androidCheckin.cellOperator = device['celloperator']
|
androidCheckin.cellOperator = self.device['celloperator']
|
||||||
androidCheckin.simOperator = device['simoperator']
|
androidCheckin.simOperator = self.device['simoperator']
|
||||||
androidCheckin.roaming = device['roaming']
|
androidCheckin.roaming = self.device['roaming']
|
||||||
androidCheckin.userNumber = 0
|
androidCheckin.userNumber = 0
|
||||||
return androidCheckin
|
return androidCheckin
|
||||||
|
|
||||||
|
|
||||||
def getAndroidCheckinRequest(device_codename):
|
|
||||||
for (key, value) in config.items(device_codename):
|
|
||||||
device[key] = value
|
|
||||||
request = googleplay_pb2.AndroidCheckinRequest()
|
|
||||||
request.id = 0
|
|
||||||
request.checkin.CopyFrom(getAndroidCheckin())
|
|
||||||
request.locale = LANG
|
|
||||||
request.timeZone = TIMEZONE
|
|
||||||
request.version = 3
|
|
||||||
request.deviceConfiguration.CopyFrom(getDeviceConfig())
|
|
||||||
request.fragment = 0
|
|
||||||
return request
|
|
||||||
|
@ -46,11 +46,12 @@ class GooglePlayAPI(object):
|
|||||||
AUTHURL = BASE + "auth"
|
AUTHURL = BASE + "auth"
|
||||||
ACCOUNT = "HOSTED_OR_GOOGLE"
|
ACCOUNT = "HOSTED_OR_GOOGLE"
|
||||||
|
|
||||||
def __init__(self, debug=False):
|
def __init__(self, debug=False, device_codename='bacon'):
|
||||||
self.authSubToken = None
|
self.authSubToken = None
|
||||||
self.gsfId = None
|
self.gsfId = None
|
||||||
self.lang = config.LANG
|
self.lang = config.LANG
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
self.deviceBuilder = config.DeviceBuilder(device_codename)
|
||||||
|
|
||||||
def encrypt_password(self, login, passwd):
|
def encrypt_password(self, login, passwd):
|
||||||
"""Encrypt the password using the google publickey, using
|
"""Encrypt the password using the google publickey, using
|
||||||
@ -87,7 +88,7 @@ class GooglePlayAPI(object):
|
|||||||
headers = {
|
headers = {
|
||||||
"Accept-Language": config.LANG.replace('_', '-'),
|
"Accept-Language": config.LANG.replace('_', '-'),
|
||||||
"X-DFE-Encoded-Targets": config.DFE_TARGETS,
|
"X-DFE-Encoded-Targets": config.DFE_TARGETS,
|
||||||
"User-Agent": config.getUserAgent()
|
"User-Agent": self.deviceBuilder.getUserAgent()
|
||||||
}
|
}
|
||||||
if self.gsfId is not None:
|
if self.gsfId is not None:
|
||||||
headers["X-DFE-Device-Id"] = "{0:x}".format(self.gsfId)
|
headers["X-DFE-Device-Id"] = "{0:x}".format(self.gsfId)
|
||||||
@ -95,11 +96,11 @@ class GooglePlayAPI(object):
|
|||||||
headers["Authorization"] = "GoogleLogin auth=%s" % self.authSubToken
|
headers["Authorization"] = "GoogleLogin auth=%s" % self.authSubToken
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
def checkin(self, email, ac2dmToken, device_codename):
|
def checkin(self, email, ac2dmToken):
|
||||||
headers = self.getDefaultHeaders()
|
headers = self.getDefaultHeaders()
|
||||||
headers["Content-Type"] = "application/x-protobuffer"
|
headers["Content-Type"] = "application/x-protobuffer"
|
||||||
|
|
||||||
request = config.getAndroidCheckinRequest(device_codename)
|
request = self.deviceBuilder.getAndroidCheckinRequest()
|
||||||
|
|
||||||
stringRequest = request.SerializeToString()
|
stringRequest = request.SerializeToString()
|
||||||
res = requests.post(self.CHECKINURL, data=stringRequest,
|
res = requests.post(self.CHECKINURL, data=stringRequest,
|
||||||
@ -125,7 +126,7 @@ class GooglePlayAPI(object):
|
|||||||
*device.properties* to the google account. Default device is a Google Nexus 6P"""
|
*device.properties* to the google account. Default device is a Google Nexus 6P"""
|
||||||
|
|
||||||
upload = googleplay_pb2.UploadDeviceConfigRequest()
|
upload = googleplay_pb2.UploadDeviceConfigRequest()
|
||||||
upload.deviceConfiguration.CopyFrom(config.getDeviceConfig())
|
upload.deviceConfiguration.CopyFrom(self.deviceBuilder.getDeviceConfig())
|
||||||
headers = self.getDefaultHeaders()
|
headers = self.getDefaultHeaders()
|
||||||
headers["X-DFE-Enabled-Experiments"] = "cl:billing.select_add_instrument_by_default"
|
headers["X-DFE-Enabled-Experiments"] = "cl:billing.select_add_instrument_by_default"
|
||||||
headers["X-DFE-Unsupported-Experiments"] = "nocache:billing.use_charging_poller,market_emails,buyer_currency,prod_baseline,checkin.set_asset_paid_app_field,shekel_test,content_ratings,buyer_currency_in_app,nocache:encrypted_apk,recent_changes"
|
headers["X-DFE-Unsupported-Experiments"] = "nocache:billing.use_charging_poller,market_emails,buyer_currency,prod_baseline,checkin.set_asset_paid_app_field,shekel_test,content_ratings,buyer_currency_in_app,nocache:encrypted_apk,recent_changes"
|
||||||
@ -137,8 +138,7 @@ class GooglePlayAPI(object):
|
|||||||
headers=headers, verify=ssl_verify)
|
headers=headers, verify=ssl_verify)
|
||||||
googleplay_pb2.ResponseWrapper.FromString(res.content)
|
googleplay_pb2.ResponseWrapper.FromString(res.content)
|
||||||
|
|
||||||
def login(self, email=None, password=None, gsfId=None,
|
def login(self, email=None, password=None, gsfId=None, authSubToken=None):
|
||||||
authSubToken=None, device_codename='bacon'):
|
|
||||||
"""Login to your Google Account.
|
"""Login to your Google Account.
|
||||||
For first time login you should provide:
|
For first time login you should provide:
|
||||||
* email
|
* email
|
||||||
@ -185,7 +185,7 @@ class GooglePlayAPI(object):
|
|||||||
else:
|
else:
|
||||||
raise LoginError("Auth token not found.")
|
raise LoginError("Auth token not found.")
|
||||||
|
|
||||||
self.gsfId = self.checkin(email, ac2dmToken, device_codename)
|
self.gsfId = self.checkin(email, ac2dmToken)
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("Google Services Framework Id: %s" % "{0:x}".format(self.gsfId))
|
print("Google Services Framework Id: %s" % "{0:x}".format(self.gsfId))
|
||||||
self.getAuthSubToken(email, encryptedPass)
|
self.getAuthSubToken(email, encryptedPass)
|
||||||
@ -496,6 +496,9 @@ class GooglePlayAPI(object):
|
|||||||
return self.delivery(packageName, versionCode,
|
return self.delivery(packageName, versionCode,
|
||||||
offerType, dlToken, progress_bar=progress_bar)
|
offerType, dlToken, progress_bar=progress_bar)
|
||||||
|
|
||||||
|
def changeDevice(self, device_codename):
|
||||||
|
self.deviceBuilder = config.DeviceBuilder(device_codename)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getDevicesCodenames():
|
def getDevicesCodenames():
|
||||||
return config.getDevicesCodenames()
|
return config.getDevicesCodenames()
|
||||||
|
Loading…
Reference in New Issue
Block a user