X-Git-Url: https://git.cweiske.de/stouyapi.git/blobdiff_plain/5af099a647da421553d00abe5a4f3d6ed21873a6..8b8ab49648debc6dd813b02094913a5ebb8167c0:/bin/import-game-data.php diff --git a/bin/import-game-data.php b/bin/import-game-data.php index 5486ef5..cfd1630 100755 --- a/bin/import-game-data.php +++ b/bin/import-game-data.php @@ -7,6 +7,7 @@ * @author Christian Weiske */ ini_set('xdebug.halt_level', E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE); +require_once __DIR__ . '/functions.php'; require_once __DIR__ . '/filters.php'; if (!isset($argv[1])) { error('Pass the path to a "folders" file with game data json files folder names'); @@ -16,10 +17,13 @@ if (!is_file($foldersFile)) { error('Given path is not a file: ' . $foldersFile); } -$GLOBALS['packagelists']['cweiskepicks'] = [ - 'de.eiswuxe.blookid2', - 'com.cosmos.babyloniantwins' -]; +//default configuration values +$GLOBALS['packagelists'] = []; +$GLOBALS['urlRewrites'] = []; +$cfgFile = __DIR__ . '/../config.php'; +if (file_exists($cfgFile)) { + include $cfgFile; +} $wwwDir = __DIR__ . '/../www/'; @@ -77,14 +81,6 @@ foreach ($gameFiles as $gameFile) { 'api/v1/games/' . $game->packageName . '/purchases', buildPurchases($game) ); - /**/ - - /* this crashes babylonian twins - writeJson( - 'api/v1/games/' . $game->packageName . '/purchases', - "{}\n" - ); - */ writeJson( 'api/v1/apps/' . $game->packageName . '.json', @@ -106,6 +102,8 @@ foreach ($gameFiles as $gameFile) { } } +calculateRank($games); + foreach ($developers as $developer) { writeJson( //index.htm does not need a rewrite rule @@ -124,9 +122,25 @@ foreach ($developers as $developer) { writeJson('api/v1/discover-data/discover.json', buildDiscover($games)); writeJson('api/v1/discover-data/home.json', buildDiscoverHome($games)); +//make +writeJson( + 'api/v1/discover-data/tutorials.json', + buildMakeCategory('Tutorials', filterByGenre($games, 'Tutorials')) +); + +$searchLetters = 'abcdefghijklmnopqrstuvwxyz0123456789., '; +foreach (str_split($searchLetters) as $letter) { + $letterGames = filterBySearchWord($games, $letter); + writeJson( + 'api/v1/search-data/' . $letter . '.json', + buildSearch($letterGames) + ); +} + function buildDiscover(array $games) { + $games = removeMakeGames($games); $data = [ 'title' => 'DISCOVER', 'rows' => [], @@ -141,9 +155,36 @@ function buildDiscover(array $games) $data, 'Best rated', filterBestRated($games, 10) ); + + foreach ($GLOBALS['packagelists'] as $listTitle => $listPackageNames) { + addDiscoverRow( + $data, $listTitle, + filterByPackageNames($games, $listPackageNames) + ); + } + addDiscoverRow( - $data, "cweiske's picks", - filterByPackageNames($games, $GLOBALS['packagelists']['cweiskepicks']) + $data, 'Special', + [ + 'Best rated', + 'Most rated', + 'Random', + ] + ); + writeJson( + 'api/v1/discover-data/' . categoryPath('Best rated') . '.json', + buildSpecialCategory('Best rated', filterBestRated($games, 99)) + ); + writeJson( + 'api/v1/discover-data/' . categoryPath('Most rated') . '.json', + buildSpecialCategory('Most rated', filterMostDownloaded($games, 99)) + ); + writeJson( + 'api/v1/discover-data/' . categoryPath('Random') . '.json', + buildSpecialCategory( + 'Random ' . date('Y-m-d H:i'), + filterRandom($games, 99) + ) ); $players = [ @@ -152,7 +193,7 @@ function buildDiscover(array $games) 3 => '3 players', 4 => '4 players', ]; - addDiscoverRow($data, '# of players', $players); + addDiscoverRow($data, 'Multiplayer', $players); foreach ($players as $num => $title) { writeJson( 'api/v1/discover-data/' . categoryPath($title) . '.json', @@ -170,7 +211,7 @@ function buildDiscover(array $games) ); } - $genres = getAllGenres($games); + $genres = removeMakeGenres(getAllGenres($games)); sort($genres); addChunkedDiscoverRows($data, $genres, 'Genres'); @@ -212,12 +253,7 @@ function buildDiscoverCategory($name, $games) filterBestRated($games, 10) ); - usort( - $games, - function ($gameA, $gameB) { - return strcmp($gameA->title, $gameB->title); - } - ); + $games = sortByTitle($games); $chunks = array_chunk($games, 4); foreach ($chunks as $chunkGames) { addDiscoverRow($data, '', $chunkGames); @@ -226,6 +262,39 @@ function buildDiscoverCategory($name, $games) return $data; } +function buildMakeCategory($name, $games) +{ + $data = [ + 'title' => $name, + 'rows' => [], + 'tiles' => [], + ]; + + $games = sortByTitle($games); + addDiscoverRow($data, '', $games); + + return $data; +} + +function buildSpecialCategory($name, $games) +{ + $data = [ + 'title' => $name, + 'rows' => [], + 'tiles' => [], + ]; + + $first3 = array_slice($games, 0, 3); + $chunks = array_chunk(array_slice($games, 3), 4); + array_unshift($chunks, $first3); + + foreach ($chunks as $chunkGames) { + addDiscoverRow($data, '', $chunkGames); + } + + return $data; +} + function buildDiscoverHome(array $games) { //we do not want anything here for now @@ -306,7 +375,7 @@ function buildAppDownload($game, $release) 'fileSize' => $release->size, 'version' => $release->uuid, 'contentRating' => $game->contentRating, - 'downloadLink' => $release->url, + 'downloadLink' => rewriteUrl($release->url), ] ]; } @@ -317,12 +386,13 @@ function buildProduct($product) return null; } return [ - 'type' => 'entitlement', + 'type' => $product->type ?? 'entitlement', 'identifier' => $product->identifier, 'name' => $product->name, 'description' => $product->description ?? '', 'localPrice' => $product->localPrice, 'originalPrice' => $product->originalPrice, + 'priceInCents' => $product->originalPrice * 100, 'percentOff' => 0, 'currency' => $product->currency, ]; @@ -350,15 +420,17 @@ function buildDetails($game) $mediaTiles[] = [ 'type' => 'image', 'urls' => [ - 'thumbnail' => $medium->thumb, + 'thumbnail' => $medium->thumb ?? $medium->url, 'full' => $medium->url, ], ]; } else { - $mediaTiles[] = [ - 'type' => 'video', - 'url' => $medium->url, - ]; + if (!isUnsupportedVideoUrl($medium->url)) { + $mediaTiles[] = [ + 'type' => 'video', + 'url' => $medium->url, + ]; + } } } @@ -377,6 +449,13 @@ function buildDetails($game) $product = buildProduct($gamePromoted); } + $iaUrl = null; + if (isset($game->latestRelease->url) + && substr($game->latestRelease->url, 0, 29) == 'https://archive.org/download/' + ) { + $iaUrl = dirname($game->latestRelease->url) . '/'; + } + // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-details return [ 'type' => 'Game', @@ -435,6 +514,10 @@ function buildDetails($game) 'promotedProduct' => $product, 'buttons' => $buttons, + + 'stouyapi' => [ + 'internet-archive' => $iaUrl, + ] ]; } @@ -489,8 +572,8 @@ function buildPurchases($game) 'purchaseDate' => time() * 1000, 'generateDate' => time() * 1000, 'identifier' => $promotedProduct->identifier, - 'gamer' => 'stouyapi', - 'uuid' => '00702342-0000-1111-2222-c3e1500cafe2',//gamer uuid + 'gamer' => '00702342-0000-1111-2222-c3e1500cafe2',//gamer uuid + 'uuid' => '00702342-0000-1111-2222-c3e1500beef3',//transaction ID 'priceInCents' => $promotedProduct->originalPrice * 100, 'localPrice' => $promotedProduct->localPrice, 'currency' => $promotedProduct->currency, @@ -502,14 +585,31 @@ function buildPurchases($game) return $encryptedTwice; } +function buildSearch($games) +{ + $games = sortByTitle($games); + $results = []; + foreach ($games as $game) { + $results[] = [ + 'title' => $game->title, + 'url' => 'ouya://launcher/details?app=' . $game->packageName, + 'contentRating' => $game->contentRating, + ]; + } + return [ + 'count' => count($results), + 'results' => $results, + ]; +} + function dummyEncrypt($data) { return [ - 'key' => base64_encode('0123456789abcdef') . "\n", - 'iv' => 't3jir1LHpICunvhlM76edQ==' . "\n",//random bytes + 'key' => base64_encode('0123456789abcdef'), + 'iv' => 't3jir1LHpICunvhlM76edQ==',//random bytes 'blob' => base64_encode( json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) - ) . "\n", + ), ]; } @@ -610,11 +710,6 @@ function buildDiscoverGameTile($game) ]; } -function categoryPath($title) -{ - return str_replace(['/', '\\', ' ', '+'], '_', $title); -} - function getAllAges($games) { $ages = []; @@ -714,6 +809,29 @@ function addMissingGameProperties($game) } } +/** + * Implements a sensible ranking system described in + * https://stackoverflow.com/a/1411268/2826013 + */ +function calculateRank(array $games) +{ + $averageRatings = array_map( + function ($game) { + return $game->rating->average; + }, + $games + ); + $average = array_sum($averageRatings) / count($averageRatings); + $C = $average; + $m = 500; + + foreach ($games as $game) { + $R = $game->rating->average; + $v = $game->rating->count; + $game->rating->rank = ($R * $v + $C * $m) / ($v + $m); + } +} + function getFirstVideoUrl($media) { foreach ($media as $medium) { @@ -748,6 +866,40 @@ function getPromotedProduct($game) return null; } +/** + * vimeo only work with HTTPS now, + * and the OUYA does not support SNI. + * We get SSL errors and no video for them :/ + */ +function isUnsupportedVideoUrl($url) +{ + return strpos($url, '://vimeo.com/') !== false; +} + +function removeMakeGames(array $games) +{ + return filterByGenre($games, 'Tutorials', true); +} + +function removeMakeGenres($genres) +{ + $filtered = []; + foreach ($genres as $genre) { + if ($genre != 'Tutorials' && $genre != 'Builds') { + $filtered[] = $genre; + } + } + return $filtered; +} + +function rewriteUrl($url) +{ + foreach ($GLOBALS['urlRewrites'] as $pattern => $replacement) { + $url = preg_replace($pattern, $replacement, $url); + } + return $url; +} + function writeJson($path, $data) { global $wwwDir;