X-Git-Url: https://git.cweiske.de/stouyapi.git/blobdiff_plain/90dc8495a939c6eedb616428ade43ce3488570d0..3771acf28944bb6d7e82bc425e7745c5524ae199:/bin/import-game-data.php diff --git a/bin/import-game-data.php b/bin/import-game-data.php index 232b11f..854b3d6 100755 --- a/bin/import-game-data.php +++ b/bin/import-game-data.php @@ -9,15 +9,36 @@ 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])) { + +//command line option parsing +$optind = null; +$opts = getopt('h', ['help', 'mini', 'noqr'], $optind); +$args = array_slice($argv, $optind); + +if (isset($opts['help']) || isset($opts['h'])) { + echo "Import games from a OUYA game data repository\n"; + echo "\n"; + echo "Usage: import-game-data.php [--mini] [--noqr] [--help|-h]\n"; + echo " --mini Generate small but ugly JSON files\n"; + echo " --noqr Do not generate and link QR code images\n"; + exit(0); +} + +if (!isset($args[0])) { error('Pass the path to a "folders" file with game data json files folder names'); } -$foldersFile = $argv[1]; +$foldersFile = $args[0]; if (!is_file($foldersFile)) { error('Given path is not a file: ' . $foldersFile); } +$cfgMini = isset($opts['mini']); +$cfgEnableQr = !isset($opts['noqr']); + + //default configuration values +$GLOBALS['baseUrl'] = 'http://ouya.cweiske.de/'; +$GLOBALS['categorySubtitles'] = []; $GLOBALS['packagelists'] = []; $GLOBALS['urlRewrites'] = []; $cfgFile = __DIR__ . '/../config.php'; @@ -27,9 +48,11 @@ if (file_exists($cfgFile)) { $wwwDir = __DIR__ . '/../www/'; -$qrDir = $wwwDir . 'gen-qr/'; -if (!is_dir($qrDir)) { - mkdir($qrDir, 0775); +if ($cfgEnableQr) { + $qrDir = $wwwDir . 'gen-qr/'; + if (!is_dir($qrDir)) { + mkdir($qrDir, 0775); + } } $baseDir = dirname($foldersFile); @@ -48,6 +71,13 @@ foreach (file($foldersFile) as $line) { } } +//store git repository version of last folder +$workdir = getcwd(); +chdir($folder); +$gitDate = `git log --max-count=1 --format="%h %cI"`; +chdir($workdir); +file_put_contents($wwwDir . '/game-data-version', $gitDate); + $games = []; $count = 0; $developers = []; @@ -142,7 +172,9 @@ foreach ($developers as $developer) { } } -writeJson('api/v1/discover-data/discover.json', buildDiscover($games)); +$data = buildDiscover($games); +writeJson('api/v1/discover-data/discover.json', $data); +writeJson('api/v1/discover-data/discover.forge.json', convertCategoryToForge($data)); writeJson('api/v1/discover-data/home.json', buildDiscoverHome($games)); //make @@ -175,8 +207,8 @@ function buildDiscover(array $games) filterLastAdded($games, 10) ); addDiscoverRow( - $data, 'Best rated', - filterBestRated($games, 10), + $data, 'Best rated games', + filterBestRatedGames($games, 10), true ); @@ -191,27 +223,32 @@ function buildDiscover(array $games) $data, 'Special', [ 'Best rated', + 'Best rated games', 'Most rated', 'Random', 'Last updated', ] ); - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath('Best rated') . '.json', buildSpecialCategory('Best rated', filterBestRated($games, 99)) ); - writeJson( + writeCategoryJson( + 'api/v1/discover-data/' . categoryPath('Best rated games') . '.json', + buildSpecialCategory('Best rated games', filterBestRatedGames($games, 99)) + ); + writeCategoryJson( 'api/v1/discover-data/' . categoryPath('Most rated') . '.json', buildSpecialCategory('Most rated', filterMostDownloaded($games, 99)) ); - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath('Random') . '.json', buildSpecialCategory( 'Random ' . date('Y-m-d H:i'), filterRandom($games, 99) ) ); - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath('Last updated') . '.json', buildSpecialCategory('Last updated', filterLastUpdated($games, 99)) ); @@ -224,7 +261,7 @@ function buildDiscover(array $games) ]; addDiscoverRow($data, 'Multiplayer', $players); foreach ($players as $num => $title) { - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath($title) . '.json', buildDiscoverCategory( $title, @@ -245,7 +282,7 @@ function buildDiscover(array $games) natsort($ages); addDiscoverRow($data, 'Content rating', $ages); foreach ($ages as $num => $title) { - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath($title) . '.json', buildDiscoverCategory($title, filterByAge($games, $title)) ); @@ -256,7 +293,7 @@ function buildDiscover(array $games) addChunkedDiscoverRows($data, $genres, 'Genres'); foreach ($genres as $genre) { - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath($genre) . '.json', buildDiscoverCategory($genre, filterByGenre($games, $genre)) ); @@ -265,7 +302,7 @@ function buildDiscover(array $games) $abc = array_merge(range('A', 'Z'), ['Other']); addChunkedDiscoverRows($data, $abc, 'Alphabetical'); foreach ($abc as $letter) { - writeJson( + writeCategoryJson( 'api/v1/discover-data/' . categoryPath($letter) . '.json', buildDiscoverCategory($letter, filterByLetter($games, $letter)) ); @@ -284,25 +321,72 @@ function buildDiscoverCategory($name, $games) 'rows' => [], 'tiles' => [], ]; - addDiscoverRow( - $data, 'Last Updated', - filterLastUpdated($games, 10) - ); - addDiscoverRow( - $data, 'Best rated', - filterBestRated($games, 10), - true - ); + if (isset($GLOBALS['categorySubtitles'][$name])) { + $data['stouyapi']['subtitle'] = $GLOBALS['categorySubtitles'][$name]; + } + + if (count($games) >= 20) { + addDiscoverRow( + $data, 'Last updated', + filterLastUpdated($games, 10) + ); + addDiscoverRow( + $data, 'Best rated', + filterBestRated($games, 10), + true + ); + } $games = sortByTitle($games); $chunks = array_chunk($games, 4); + $title = 'All'; foreach ($chunks as $chunkGames) { - addDiscoverRow($data, '', $chunkGames); + addDiscoverRow($data, $title, $chunkGames); + $title = ''; } return $data; } +/** + * Modify a category to make it suitable for the Razer Forge TV + * + * - Fold rows without title into the previous row + * - Remove automatically generated categories ("Last updated", "Best rated") + * + * @see buildDiscoverCategory() + */ +function convertCategoryToForge($data, $removeAutoCategories = false) +{ + //merge tiles from rows without title into the previous row + $lastTitleRowId = null; + foreach ($data['rows'] as $rowId => $row) { + if ($row['title'] !== '') { + $lastTitleRowId = $rowId; + } else if ($lastTitleRowId !== null) { + $data['rows'][$lastTitleRowId]['tiles'] = array_merge( + $data['rows'][$lastTitleRowId]['tiles'], + $row['tiles'] + ); + unset($data['rows'][$rowId]); + } + } + + if ($removeAutoCategories) { + foreach ($data['rows'] as $rowId => $row) { + if ($row['title'] === 'Last updated' + || $row['title'] === 'Best rated' + ) { + unset($data['rows'][$rowId]); + } + } + } + + $data['rows'] = array_values($data['rows']); + + return $data; +} + function buildMakeCategory($name, $games) { $data = [ @@ -431,7 +515,7 @@ function buildAppDownload($game, $release) 'fileSize' => $release->size, 'version' => $release->uuid, 'contentRating' => $game->contentRating, - 'downloadLink' => rewriteUrl($release->url), + 'downloadLink' => $release->url, ] ]; } @@ -512,11 +596,18 @@ function buildDetails($game, $linkDeveloperPage = false) $iaUrl = dirname($game->latestRelease->url) . '/'; } + $description = $game->description; + if (isset($game->notes) && trim($game->notes)) { + $description = "Technical notes:\r\n" . $game->notes + . "\r\n----\r\n" + . $description; + } + // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-details $data = [ 'type' => 'Game', 'title' => $game->title, - 'description' => $game->description, + 'description' => $description, 'gamerNumbers' => $game->players, 'genres' => $game->genres, @@ -797,6 +888,8 @@ function getAllGenres($games) function addMissingGameProperties($game) { + global $cfgEnableQr; + if (!isset($game->overview)) { $game->overview = null; } @@ -840,6 +933,9 @@ function addMissingGameProperties($game) $firstReleaseTimestamp = null; $latestReleaseTimestamp = 0; foreach ($game->releases as $release) { + if (isset($release->broken) && $release->broken) { + continue; + } if (!isset($release->publicSize)) { $release->publicSize = 0; } @@ -886,7 +982,7 @@ function addMissingGameProperties($game) $game->developer->founder = false; } - if ($game->website) { + if ($cfgEnableQr && $game->website) { $qrfileName = preg_replace('#[^\\w\\d._-]#', '_', $game->website) . '.png'; $qrfilePath = $GLOBALS['qrDir'] . $qrfileName; if (!file_exists($qrfilePath)) { @@ -898,12 +994,21 @@ function addMissingGameProperties($game) exit(20); } } - $qrUrlPath = '/gen-qr/' . $qrfileName; + $qrUrlPath = $GLOBALS['baseUrl'] . 'gen-qr/' . $qrfileName; $game->media[] = (object) [ 'type' => 'image', 'url' => $qrUrlPath, ]; } + + //rewrite urls from Internet Archive to our servers + $game->discover = rewriteUrl($game->discover); + foreach ($game->media as $medium) { + $medium->url = rewriteUrl($medium->url); + } + foreach ($game->releases as $release) { + $release->url = rewriteUrl($release->url); + } } /** @@ -999,18 +1104,31 @@ function rewriteUrl($url) function writeJson($path, $data) { - global $wwwDir; + global $cfgMini, $wwwDir; $fullPath = $wwwDir . $path; $dir = dirname($fullPath); if (!is_dir($dir)) { mkdir($dir, 0777, true); } + $opts = JSON_UNESCAPED_SLASHES; + if (!$cfgMini) { + $opts |= JSON_PRETTY_PRINT; + } file_put_contents( $fullPath, - json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n" + json_encode($data, $opts) . "\n" ); } +function writeCategoryJson($path, $data) +{ + writeJson($path, $data); + + $forgePath = str_replace('.json', '.forge.json', $path); + $forgeData = convertCategoryToForge($data, true); + writeJson($forgePath, $forgeData); +} + function error($msg) { fwrite(STDERR, $msg . "\n");