X-Git-Url: https://git.cweiske.de/stouyapi.git/blobdiff_plain/73cdf5c2b6aef748803efa1ba0394b264171c2a7..7ddab9bf8fe51936011321ffd881adc0e7be5b58:/bin/import-game-data.php diff --git a/bin/import-game-data.php b/bin/import-game-data.php index a02dad7..6672409 100755 --- a/bin/import-game-data.php +++ b/bin/import-game-data.php @@ -6,62 +6,225 @@ * @link https://github.com/cweiske/ouya-game-data/ * @author Christian Weiske */ +ini_set('xdebug.halt_level', E_WARNING|E_NOTICE|E_USER_WARNING|E_USER_NOTICE); +require_once __DIR__ . '/filters.php'; if (!isset($argv[1])) { - error('Pass the path to a directory with game data json files'); + error('Pass the path to a "folders" file with game data json files folder names'); } -$gameDataDir = $argv[1]; -if (!is_dir($gameDataDir)) { - error('Given path is not a directory: ' . $gameDataDir); +$foldersFile = $argv[1]; +if (!is_file($foldersFile)) { + error('Given path is not a file: ' . $foldersFile); } +$GLOBALS['packagelists']['cweiskepicks'] = [ + 'de.eiswuxe.blookid2', + 'com.cosmos.babyloniantwins' +]; + $wwwDir = __DIR__ . '/../www/'; -$gameFiles = glob($gameDataDir . '/*.json'); +$baseDir = dirname($foldersFile); +$gameFiles = []; +foreach (file($foldersFile) as $line) { + $line = trim($line); + if (strlen($line)) { + if (strpos($line, '..') !== false) { + error('Path attack in ' . $folder); + } + $folder = $baseDir . '/' . $line; + if (!is_dir($folder)) { + error('Folder does not exist: ' . $folder); + } + $gameFiles = array_merge($gameFiles, glob($folder . '/*.json')); + } +} + $games = []; +$count = 0; foreach ($gameFiles as $gameFile) { $game = json_decode(file_get_contents($gameFile)); if ($game === null) { error('JSON invalid at ' . $gameFile); } addMissingGameProperties($game); - //FIXME: add missing properties? - $games[$game->package] = $game; + $games[$game->packageName] = $game; + + writeJson( + 'api/v1/details-data/' . $game->packageName . '.json', + buildDetails($game) + ); + /* this crashes babylonian twins + writeJson( + 'api/v1/games/' . $game->packageName . '/purchases', + "{}\n" + ); + */ + writeJson( - 'api/v1/apps/' . $game->package, + 'api/v1/apps/' . $game->packageName . '.json', buildApps($game) ); + $latestRelease = $game->latestRelease; writeJson( - 'api/v1/details-data/' . $game->package . '.json', - buildDetails($game) + 'api/v1/apps/' . $latestRelease->uuid . '.json', + buildApps($game) + ); + + writeJson( + 'api/v1/apps/' . $latestRelease->uuid . '-download.json', + buildAppDownload($game, $latestRelease) + ); + + if ($count++ > 20) { + //break; + } +} + +writeJson('api/v1/discover.json', buildDiscover($games)); +writeJson('api/v1/discover-data/home.json', buildDiscoverHome($games)); + + +function buildDiscover(array $games) +{ + $data = [ + 'title' => 'DISCOVER', + 'rows' => [], + 'tiles' => [], + ]; + + addDiscoverRow( + $data, 'Last Updated', + filterLastUpdated($games, 10) + ); + addDiscoverRow( + $data, 'Best rated', + filterBestRated($games, 10) + ); + addDiscoverRow( + $data, "cweiske's picks", + filterByPackageNames($games, $GLOBALS['packagelists']['cweiskepicks']) ); - //exit(2); + $players = [ + //1 => '1 player', + 2 => '2 players', + 3 => '3 players', + 4 => '4 players', + ]; + addDiscoverRow($data, '# of players', $players); + foreach ($players as $num => $title) { + writeJson( + 'api/v1/discover-data/' . categoryPath($title) . '.json', + buildDiscoverCategory($title, filterByPlayers($games, $num)) + ); + } + + $ages = getAllAges($games); + natsort($ages); + addDiscoverRow($data, 'Content rating', $ages); + foreach ($ages as $num => $title) { + writeJson( + 'api/v1/discover-data/' . categoryPath($title) . '.json', + buildDiscoverCategory($title, filterByAge($games, $title)) + ); + } + + $genres = getAllGenres($games); + sort($genres); + addChunkedDiscoverRows($data, $genres, 'Genres'); + + foreach ($genres as $genre) { + writeJson( + 'api/v1/discover-data/' . categoryPath($genre) . '.json', + buildDiscoverCategory($genre, filterByGenre($games, $genre)) + ); + } + + $abc = array_merge(range('A', 'Z'), ['Other']); + addChunkedDiscoverRows($data, $abc, 'Alphabetical'); + foreach ($abc as $letter) { + writeJson( + 'api/v1/discover-data/' . categoryPath($letter) . '.json', + buildDiscoverCategory($letter, filterByLetter($games, $letter)) + ); + } + + return $data; +} + +/** + * A genre category page + */ +function buildDiscoverCategory($name, $games) +{ + $data = [ + 'title' => $name, + 'rows' => [], + 'tiles' => [], + ]; + addDiscoverRow( + $data, 'Last Updated', + filterLastUpdated($games, 10) + ); + addDiscoverRow( + $data, 'Best rated', + filterBestRated($games, 10) + ); + + usort( + $games, + function ($gameA, $gameB) { + return strcmp($gameB->title, $gameA->title); + } + ); + $chunks = array_chunk($games, 4); + foreach ($chunks as $chunkGames) { + addDiscoverRow($data, '', $chunkGames); + } + + return $data; } -//FIXME: build discover section +function buildDiscoverHome(array $games) +{ + //we do not want anything here for now + $data = [ + 'title' => 'home', + 'rows' => [ + [ + 'title' => 'FEATURED', + 'showPrice' => false, + 'ranked' => false, + 'tiles' => [], + ] + ], + 'tiles' => [], + ]; + return $data; +} /** - * Build api/v1/apps/$package + * Build api/v1/apps/$packageName */ function buildApps($game) { - $latestRelease = getLatestRelease($game); - + $latestRelease = $game->latestRelease; + // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-apps-xxx return [ 'app' => [ - 'uuid' => $game->uuid, + 'uuid' => $latestRelease->uuid, 'title' => $game->title, 'overview' => $game->overview, 'description' => $game->description, 'gamerNumbers' => $game->players, 'genres' => $game->genres, - + 'website' => $game->website, 'contentRating' => $game->contentRating, 'premium' => $game->premium, 'firstPublishedAt' => $game->firstPublishedAt, - + 'likeCount' => $game->rating->likeCount, 'ratingAverage' => $game->rating->average, 'ratingCount' => $game->rating->count, @@ -74,7 +237,7 @@ function buildApps($game) 'publicSize' => $latestRelease->publicSize, 'nativeSize' => $latestRelease->nativeSize, - 'mainImageFullUrl' => $game->media->large, + 'mainImageFullUrl' => $game->media->discover, 'videoUrl' => $game->media->video, 'filepickerScreenshots' => $game->media->screenshots, 'mobileAppIcon' => null, @@ -89,22 +252,34 @@ function buildApps($game) ]; } +function buildAppDownload($game, $release) +{ + return [ + 'app' => [ + 'fileSize' => $release->size, + 'version' => $release->uuid, + 'contentRating' => $game->contentRating, + 'downloadLink' => $release->url, + ] + ]; +} + /** * Build /app/v1/details?app=org.example.game */ function buildDetails($game) { - $latestRelease = getLatestRelease($game); + $latestRelease = $game->latestRelease; $mediaTiles = []; - if ($game->media->large) { + if ($game->media->discover) { $mediaTiles[] = [ 'type' => 'image', 'urls' => [ - 'thumbnail' => $game->media->large, - 'full' => $game->media->large, + 'thumbnail' => $game->media->discover, + 'full' => $game->media->discover, ], - 'fp_url' => $game->media->large, + 'fp_url' => $game->media->discover, ]; } if ($game->media->video) { @@ -123,7 +298,7 @@ function buildDetails($game) 'fp_url' => $screenshot, ]; } - + // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-details return [ 'type' => 'Game', @@ -150,7 +325,7 @@ function buildDetails($game) 'md5sum' => $latestRelease->md5sum, 'filename' => 'FIXME', 'errors' => '', - 'package' => $game->package, + 'package' => $game->packageName, 'versionCode' => $latestRelease->versionCode, 'state' => 'complete', ], @@ -179,9 +354,123 @@ function buildDetails($game) 'heroImage' => [ 'url' => null, ], - + + 'promotedProduct' => null, + ]; +} + +function addChunkedDiscoverRows(&$data, $games, $title) +{ + $chunks = array_chunk($games, 4); + $first = true; + foreach ($chunks as $chunk) { + addDiscoverRow( + $data, $first ? $title : '', + $chunk + ); + $first = false; + } +} + +function addDiscoverRow(&$data, $title, $games) +{ + $row = [ + 'title' => $title, + 'showPrice' => false, + 'ranked' => false, + 'tiles' => [], + ]; + foreach ($games as $game) { + if (is_string($game)) { + //category link + $tilePos = count($data['tiles']); + $data['tiles'][$tilePos] = buildDiscoverCategoryTile($game); + + } else { + //game + $tilePos = findTile($data['tiles'], $game->packageName); + if ($tilePos === null) { + $tilePos = count($data['tiles']); + $data['tiles'][$tilePos] = buildDiscoverGameTile($game); + } + } + $row['tiles'][] = $tilePos; + } + $data['rows'][] = $row; +} + +function findTile($tiles, $packageName) +{ + foreach ($tiles as $pos => $tile) { + if ($tile['package'] == $packageName) { + return $pos; + } + } + return null; +} + +function buildDiscoverCategoryTile($title) +{ + return [ + 'url' => 'ouya://launcher/discover/' . categoryPath($title), + 'image' => '', + 'title' => $title, + 'type' => 'discover' + ]; +} + +function buildDiscoverGameTile($game) +{ + $latestRelease = $game->latestRelease; + return [ + 'gamerNumbers' => $game->players, + 'genres' => $game->genres, + 'url' => 'ouya://launcher/details?app=' . $game->packageName, + 'latestVersion' => [ + 'apk' => [ + 'md5sum' => $latestRelease->md5sum, + ], + 'versionNumber' => $latestRelease->name, + 'uuid' => $latestRelease->uuid, + ], + 'inAppPurchases' => $game->inAppPurchases, 'promotedProduct' => null, - ]; + 'premium' => $game->premium, + 'type' => 'app', + 'package' => $game->packageName, + 'updated_at' => strtotime($latestRelease->date), + 'updatedAt' => $latestRelease->date, + 'title' => $game->title, + 'image' => $game->media->discover, + 'contentRating' => $game->contentRating, + 'rating' => [ + 'count' => $game->rating->count, + 'average' => $game->rating->average, + ], + ]; +} + +function categoryPath($title) +{ + return str_replace(['/', '\\', ' ', '+'], '_', $title); +} + +function getAllAges($games) +{ + $ages = []; + foreach ($games as $game) { + $ages[] = $game->contentRating; + } + return array_unique($ages); +} + +function getAllGenres($games) +{ + $genres = []; + foreach ($games as $game) { + $genres = array_merge($genres, $game->genres); + } + return array_unique($genres); } function addMissingGameProperties($game) @@ -210,7 +499,7 @@ function addMissingGameProperties($game) if (!isset($game->firstPublishedAt)) { $game->firstPublishedAt = gmdate('c'); } - + if (!isset($game->rating)) { $game->rating = new stdClass(); } @@ -224,6 +513,8 @@ function addMissingGameProperties($game) $game->rating->count = 0; } + $game->latestRelease = null; + $latestReleaseTimestamp = 0; foreach ($game->releases as $release) { if (!isset($release->publicSize)) { $release->publicSize = 0; @@ -231,6 +522,15 @@ function addMissingGameProperties($game) if (!isset($release->nativeSize)) { $release->nativeSize = 0; } + + $releaseTimestamp = strtotime($release->date); + if ($releaseTimestamp > $latestReleaseTimestamp) { + $game->latestRelease = $release; + $latestReleaseTimestamp = $releaseTimestamp; + } + } + if ($game->latestRelease === null) { + error('No latest release for ' . $game->packageName); } if (!isset($game->media->video)) { @@ -256,21 +556,6 @@ function addMissingGameProperties($game) } } -function getLatestRelease($game) -{ - $latestRelease = null; - foreach ($game->releases as $release) { - if ($release->latest ?? false) { - $latestRelease = $release; - break; - } - } - if ($latestRelease === null) { - error('No latest release for ' . $game->package); - } - return $latestRelease; -} - function writeJson($path, $data) { global $wwwDir;