/classes/AndroidMarket.class.php

https://gitlab.com/billyprice1/app-download.org · PHP · 130 lines · 81 code · 17 blank · 32 comment · 5 complexity · 2200bda9e3ffa81afac73c24991f8533 MD5 · raw file

  1. <?php
  2. require_once(__DIR__ . '/../proto/download.php');
  3. require_once(__DIR__ . '/../proto/error.php');
  4. class DownloadFailedException extends Exception {}
  5. class DownloadPreparationFailedException extends Exception {}
  6. class AndroidMarket
  7. {
  8. protected $login;
  9. protected $auth;
  10. public $deviceid;
  11. public function __construct(GoogleAccount $login, $deviceid)
  12. {
  13. $this->login = $login;
  14. $this->deviceid = $deviceid;
  15. $logindata = $this->login->login('androidmarket');
  16. if (!isset($logindata['auth'])) {
  17. throw new GoogleLoginFailedException(_('Login failed: No auth key received.'));
  18. }
  19. $this->auth = $logindata['auth'];
  20. }
  21. /**
  22. * Fetch the download information for given package.
  23. *
  24. * @param string $package
  25. * The package to download.
  26. *
  27. * @return array
  28. * Array containing the download url, cookie and package name.
  29. * For example: array(
  30. * 'url' => 'http://android.clients.google.com/ ...',
  31. * 'marketda' => 'MarketDA=34a2 ...',
  32. * 'package' => 'com.netflix.mediaclient',
  33. * );
  34. *
  35. * @throws DownloadPreparationFailedException
  36. * If something goes wrong during preparation of download.
  37. */
  38. public function fetchDownloadInfo($package)
  39. {
  40. $query = array(
  41. 'doc' => $package,
  42. );
  43. $curl = curl_init();
  44. curl_setopt($curl, CURLOPT_URL, 'https://android.clients.google.com/fdfe/purchase');
  45. curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($query));
  46. curl_setopt($curl, CURLOPT_USERAGENT,
  47. 'Android-Finsky/4.6.17 (api=3,versionCode=80260017)');
  48. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  49. "Authorization: GoogleLogin auth=$this->auth",
  50. "X-DFE-Device-Id: $this->deviceid"
  51. ));
  52. curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
  53. curl_setopt($curl, CURLOPT_BINARYTRANSFER, TRUE);
  54. curl_setopt($curl, CURLOPT_TIMEOUT, 10);
  55. // Get result and status code of request.
  56. $httpresult = curl_exec($curl);
  57. $httpstatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  58. curl_close($curl);
  59. if ($httpstatus === 28) {
  60. throw new DownloadPreparationFailedException(_('Failed to fetch download information: Request timed out.'));
  61. } elseif ($httpstatus !== 200) {
  62. mail(ERROR_MAIL, 'Download Failed', "Package:$package\nHTTP-Status:$httpstatus\n\n$httpresult");
  63. throw new DownloadPreparationFailedException(_(
  64. "Oh no! Something went wrong. Possible reasons are:
  65. 1. The app might no longer be available on the Play Store.
  66. 2. App-Download.org usually simulates a Nexus 5. The app might not be available for that device.
  67. Please excuse this incident. The administrator has been notified."
  68. ));
  69. }
  70. // Get marketda cookie and download url from response.
  71. try {
  72. // Walk through nested messages.
  73. $message_a = new DownloadMessageA($httpresult);
  74. $message_b = $message_a->getNext();
  75. $message_c = $message_b->getNext();
  76. $message_d = $message_c->getNext();
  77. $downloadinfo = $message_d->getDownloadInformation();
  78. // Get download information.
  79. $url = $downloadinfo->getUrl();
  80. $marketda = $downloadinfo->getCookie()->getValue();
  81. if (empty($url) || empty($marketda)) {
  82. throw new \DrSlump\Protobuf\Exception();
  83. }
  84. } catch (\DrSlump\Protobuf\Exception $e) {
  85. throw new DownloadPreparationFailedException(_('Could not get download information for given package.'));
  86. }
  87. return array(
  88. 'url' => $url,
  89. 'marketda' => $marketda,
  90. 'package' => $package,
  91. );
  92. }
  93. /**
  94. * Download app from given location
  95. * with given download information.
  96. *
  97. * @param string $url
  98. * The url from where to download.
  99. *
  100. * @param $marketda
  101. * The MarketDA cookie to use for the download.
  102. */
  103. public static function download($url, $marketda)
  104. {
  105. // Use curl to pass through the apk to the user.
  106. $curl = curl_init();
  107. curl_setopt($curl, CURLOPT_URL, $url);
  108. curl_setopt($curl, CURLOPT_COOKIE, "MarketDA=$marketda");
  109. curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
  110. curl_exec($curl);
  111. curl_close($curl);
  112. }
  113. }