Файл: gapps/src/Lib/Api/GoogleApps.php
Строк: 691
<?php
namespace LibApi;
/**
* LibApiGoogleApps
*
* __DESCRIPTION__
*
* @package namespace LibApi;
* @category GoogleApps
* @author Anthony Pillos <dev.anthonypillos@gmail.com>
* @copyright Copyright (c) 2017
* @version v1
*/
use Cache;
use CarbonCarbon;
use SymfonyComponentDomCrawlerCrawler;
use CampoUserAgent;
use GuzzleHttpClient;
use GuzzleHttpExceptionClientException;
use GuzzleHttpExceptionGuzzleException;
use Exception;
class GoogleApps
{
private $url = 'https://play.google.com';
private $appUrl = 'https://play.google.com/store/apps';
public $filters = [
'top_free' => 'topselling_free',
'top_paid' => 'topselling_paid',
'new_free' => 'topselling_new_free',
'new_paid' => 'topselling_new_paid',
'grossing' => 'topgrossing',
'trending' => 'movers_shakers',
];
// public $sort = [
// 'newest' => 0,
// 'rating' => 1,
// 'helpfulness' => 2
// ];
// public $age = [
// 'five_under' => 'AGE_RANGE1',
// 'six_eight' => 'AGE_RANGE2',
// 'nine_up' => 'AGE_RANGE3',
// ];
public $opts = [
'lang' => 'en',
'country' => 'us',
'start' => 0,
'max_result' => 60
];
private $webClient;
/**
* __construct()
* Initialize our Class Here for Dependecy Injection
*
* @return void
* @access public
**/
public function __construct()
{
$this->opts['lang'] = env('SET_LOCALE');
$this->webClient = new Client(array(
'headers' => array('User-Agent' => UserAgent::random())
));
}
/**
* setOptions()
*
*
* @return void
* @access public
**/
public function setOptions($opt = [])
{
$opts = array_merge($this->opts,$opt);
$this->opts = $opts;
return $this;
}
/**
* topApps()
*
*
* @return void
* @access public
**/
public function topApps()
{
$this->appUrl .= '/top'.'?hl='.$this->opts['lang'].'&gl='.$this->opts['country'];
$that = $this;
$content = Cache::remember('top_apps', 1500, function() use ($that) {
$response = $that->webClient->get($that->appUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$response = $crawler->filter('div.browse-page .cluster-container')
->each(function(Crawler $crawler,$i) use($that) {
$name = trim($crawler->filter('a.title-link')->text());
$identifier = str_slug($name);
$linkUrl = array_filter(explode('/', $crawler->filter('a.title-link')->attr('href')));
$link = route('frontend.collection',isset($linkUrl[4]) ? $linkUrl[4] : '#');
if( isset($linkUrl[5]) && isset($linkUrl[6]) )
$link = route('frontend.category',[$linkUrl[4],$linkUrl[5].DIRECTORY_SEPARATOR.$linkUrl[6] ]);
$topArr = [
'name' => $name,
'link' => $link
];
$apps = $crawler->filter('div.card-content')->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$topArr['apps'] = $apps;
return $topArr;
});
return $response;
});
return $content;
}
/**
* lists()
*
* @return void
* @access public
**/
public function lists($filter = 'movers_shakers')
{
$this->appUrl .= '/collection/'.$filter;
$this->appUrl .= '?start='.$this->opts['start'].'&num='.$this->opts['max_result'].'&hl='.$this->opts['lang'].'&gl='.$this->opts['country'];
try {
$response = $this->webClient->get($this->appUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$name = trim($crawler->filter('.cluster-heading h2')->text());
$content = $crawler->filter('div.card-content')->each(function(Crawler $node,$i) use ($filter){
return $this->cardContent($node);
});
return [
'name' => $name,
'apps' => $content
];
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* detail()
*
* @return void
* @access public
**/
public function details($appId,$opts = [])
{
if(!$appId)
throw new Exception("No App Url Found", 1);
$options = array_merge($this->opts,$opts);
$params = [
'id' => $appId,
'hl' => $options['lang'],
'gl' => $options['country'],
];
$query = http_build_query($params);
$detailUrl = $this->appUrl.'/details?'.$query;
try {
$that = $this;
$content = Cache::remember(str_slug(trim($appId)) , 1500, function() use ($that,$detailUrl,$query) {
$response = $this->webClient->get($detailUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$detailInfo = $crawler->filter('div.details-wrapper');
$additionalDetail = $crawler->filter('.details-section-contents');
$currentVersion = $additionalDetail->filter('div.content[itemprop="softwareVersion"]')->count() > 0 ? $additionalDetail->filter('div.content[itemprop="softwareVersion"]')->text() : 0;
$totalInstall = $additionalDetail->filter('div.content[itemprop="numDownloads"]')->count() > 0 ? $additionalDetail->filter('div.content[itemprop="numDownloads"]')->text() : 0;
$ratingHistorgram = $additionalDetail
->filter('.rating-histogram .rating-bar-container')
->each(function(Crawler $node,$i){
return [
'num' => trim($node->filter('.bar-label')->text()),
'bar_length' => trim($node->filter('.bar')->attr('style')),
'bar_number' => trim($node->filter('.bar-number')->text()),
];
});
$commentArr = $additionalDetail->filter('.single-review')
->each(function(Crawler $node,$i){
$authorImg = $node->filter('.author-image')->attr('style');
preg_match('/(([^)]+))/', $authorImg, $match);
return [
'author' => $node->filter('.author-name')->text(),
'published_date' => $node->filter('.review-date')->text(),
'comments' => $node->filter('.review-body')->text(),
'image' => @$match[1],
];
});
$similarApps = $crawler->filter('.secondary-content .recommendation .card-content')
->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$moreFromDeveloper = $crawler->filter('.more-from-developer .recommendation .card-content')
->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$similarCollections = collect($similarApps);
$similarRandom = $similarCollections->count() <= 5 ? $similarCollections : $similarCollections->random(5)->values();
$developerCollections = collect($moreFromDeveloper);
$moreFromDeveloperRandom = $developerCollections->count() <= 5 ? $developerCollections : $developerCollections->random(5)->values();
$linkUrl = array_filter(explode('/', $detailInfo->filter('.category')->first()->attr('href') ));
$link = route('frontend.category',isset($linkUrl[4]) ? $linkUrl[4] : '#');
$appTitle = trim($detailInfo->filter('.document-title')->text());
$detailArray = [
'app_url' => route('frontend.download',str_slug($appTitle)).'?token='.base64_encode($query),
'app_link' => $detailUrl,
'title' => $appTitle,
'short_summary' => $crawler->filter('meta[name="description"]')->attr('content'),
'description' => $detailInfo->filter('div.show-more-content > div')->html(),
'cover_image' => $detailInfo->filter('img.cover-image')->attr('src'),
'developer' => [
'link' => $this->parseDeveloperLink( $detailInfo->filter('div[itemprop="author"] a.document-subtitle')->attr('href') ),
'name' => $detailInfo->filter('span[itemprop="name"]')->text()
],
'category' => [
'name' => trim($detailInfo->filter('.category')->first()->text()),
'link' => $link
],
'updated_at' => trim($additionalDetail->filter('div.content[itemprop="datePublished"]')->text()),
'required_android' => trim($additionalDetail->filter('div.content[itemprop="operatingSystems"]')->text()),
'current_version' => trim($currentVersion),
'installs' => trim($totalInstall),
'reviews' => [
'rating_count' => $additionalDetail->filter('.rating-box span.reviews-num')->text(),
'rate_score' => trim($additionalDetail->filter('.score-container .score')->text()),
'rating_histogram' => $ratingHistorgram,
'comments' => $commentArr
],
'similar_apps' => $similarRandom,
'more_from_developer' => $moreFromDeveloperRandom,
'screenshots' => $detailInfo->filter('.thumbnails .screenshot')->extract('src'),
'price' => $detailInfo->filter('meta[itemprop=price]')->attr('content'),
];
// pre($detailArray);
// exit;
return $detailArray;
});
return $content;
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* developerLists()
*
* @return void
* @access public
**/
public function developerLists($developerId)
{
if(!$developerId)
throw new Exception("No Developer Id Found", 1);
$this->appUrl .='/developer?id='.$developerId.'&hl='.$this->opts['lang'];
try {
$cacheName = sprintf('%s-%s',$developerId,$this->opts['lang']);
$that = $this;
$content = Cache::remember( str_slug(trim($cacheName)) , 1500, function() use ($that) {
$response = $this->webClient->get($this->appUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$that = $this;
$content = $crawler->filter('div.card-content')
->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
return $content;
});
return $content;
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* byCategory()
*
* @return void
* @access public
**/
public function byCategory($categoryId,$collection = null,$type =null)
{
if(!$categoryId)
throw new Exception("No Category Id Found", 1);
$this->appUrl .='/category/'.$categoryId;
if($collection && $type)
{
$collectionName = DIRECTORY_SEPARATOR.$collection.DIRECTORY_SEPARATOR.$type;
return $this->byCategoryCollection($collectionName,$categoryId);
}
$cacheName = sprintf('%s-%s',$categoryId,$this->opts['lang']);
$this->appUrl .='?hl='.$this->opts['lang'];
try {
$that = $this;
$categories = Cache::remember( str_slug(trim($cacheName)) , 1500, function() use ($that) {
$response = $this->webClient->get($this->appUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$that = $this;
$categories = $crawler->filter('div.browse-page .cluster-container')
->each(function(Crawler $crawler,$i) use($that) {
$name = trim($crawler->filter('a.title-link')->text());
$identifier = str_slug($name);
$linkUrl = array_filter(explode('/', $crawler->filter('a.title-link')->attr('href')));
$topArr = [
'name' => $name,
'link' => route('frontend.collection',isset($linkUrl[4]) ? $linkUrl[4] : '#')
];
$apps = $crawler->filter('div.card-content')->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$topArr['apps'] = $apps;
return $topArr;
});
return $categories;
});
return $categories;
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* byCategory()
*
* @return void
* @access public
**/
public function byCategoryCollection($collectionName,$categoryId = null)
{
try {
$this->appUrl .= $collectionName;
$this->appUrl .='?hl='.$this->opts['lang'];
$that = $this;
$cacheName = sprintf('%s-%s-%s',$categoryId,str_slug($collectionName),$this->opts['lang']);
$categories = Cache::remember($cacheName , 1500, function() use ($that) {
$response = $this->webClient->get($this->appUrl);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$that = $this;
$topArr = [
'name' => trim($crawler->filter('.cluster-container h2')->text())
];
$apps = $crawler->filter('div.card-content')->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$topArr['apps'] = $apps;
// pre($topArr);
// exit;
return [$topArr];
});
return $categories;
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* search()
*
* @return void
* @access public
**/
public function search($q)
{
try {
$this->url .= '/store/search?c=apps&q='.$q.'&hl='.$this->opts['lang'];
$that = $this;
$searchResults = Cache::remember( str_slug(trim($q)) , 1, function() use ($that) {
$response = $this->webClient->get($this->url);
$content = $response->getBody()->getContents();
$crawler = new Crawler($content);
$topArr = [
'name' => trim($crawler->filter('.cluster-container h2 a')->text())
];
$apps = $crawler->filter('div.card-content')->each(function(Crawler $node,$i) use($that) {
return $that->cardContent($node);
});
$topArr['apps'] = $apps;
return $topArr;
});
return $searchResults;
} catch (GuzzleException $e) {
if ($e instanceof ClientException && $e->hasResponse()) {
throw new Exception($e->getResponse()->getReasonPhrase(), 3);
}
else
throw new Exception($e->getMessage(), 3);
}
}
/**
* cardContent()
*
* @return void
* @access private
**/
private function cardContent($node)
{
$title = $this->hasData($node->filter('a.title')) != false ? $node->filter('a.title')->attr('title') : '';
$description = $this->hasData($node->filter('div.description')) != false ? trim($node->filter('div.description')->text()) : '';
$link = $this->hasData($node->filter('a.title')) != false ? $node->filter('a.title')->attr('href') : '';
$developer_link = $this->hasData($node->filter('div.subtitle-container a.subtitle')) != false ? $node->filter('div.subtitle-container a.subtitle')->attr('href') : '';
$developer_name = $this->hasData($node->filter('div.subtitle-container a.subtitle')) != false ? $node->filter('div.subtitle-container a.subtitle')->attr('title') : '';
$image_l = $this->hasData($node->filter('div.cover-image-container img')) != false ? $node->filter('div.cover-image-container img')->attr('data-cover-large') : '';
$image_m = $this->hasData($node->filter('div.cover-image-container img')) != false ? $node->filter('div.cover-image-container img')->attr('data-cover-small') : '';
$ratings = $this->hasData($node->filter('div.tiny-star')) != false ? $node->filter('div.tiny-star')->attr('aria-label') : 0;
$price = $this->hasData($node->filter('span.display-price')) != false ? $node->filter('span.display-price')->text() : 'Free';
$appId = $node->attr('data-docid');
return [
'title' => $title,
'description' => $description,
'link' => $this->url.$link,
'app_id' => $appId,
'developer' => [
'link' => $this->parseDeveloperLink($developer_link),
'name' => $developer_name
],
'image' => [
'large' => $image_l,
'small' => $image_m,
],
'ratings' => numberInAString($ratings),
'price' => $price,
'detail_url' => route('frontend.detail',str_slug($title)).'?appid='.$appId
];
}
/**
* hasData()
*
* @return void
* @access private
**/
private function hasData($filterNode)
{
if($filterNode->count() > 0)
return $filterNode;
return false;
}
/**
* parseDeveloperLink()
*
* @return void
* @access private
**/
private function parseDeveloperLink($link)
{
$developerLink = '#';
$devOpsParts = parse_url($link);
if(isset($devOpsParts['query']))
parse_str($devOpsParts['query'], $developerLink);
return route('frontend.developer',$developerLink);
}
}