First working version with downloads
[stouyapi.git] / bin / import-game-data.php
1 #!/usr/bin/env php
2 <?php
3 /**
4  * Import games from a OUYA game data repository
5  *
6  * @link https://github.com/cweiske/ouya-game-data/
7  * @author Christian Weiske <cweiske@cweiske.de>
8  */
9 if (!isset($argv[1])) {
10     error('Pass the path to a directory with game data json files');
11 }
12 $gameDataDir = $argv[1];
13 if (!is_dir($gameDataDir)) {
14     error('Given path is not a directory: ' . $gameDataDir);
15 }
16
17 $wwwDir = __DIR__ . '/../www/';
18
19 $gameFiles = glob($gameDataDir . '/*.json');
20 $games = [];
21 foreach ($gameFiles as $gameFile) {
22     $game = json_decode(file_get_contents($gameFile));
23     if ($game === null) {
24         error('JSON invalid at ' . $gameFile);
25     }
26     addMissingGameProperties($game);
27     $games[$game->package] = $game;
28
29     writeJson(
30         'api/v1/details-data/' . $game->package . '.json',
31         buildDetails($game)
32     );
33     
34     writeJson(
35         'api/v1/apps/' . $game->package . '.json',
36         buildApps($game)
37     );
38     $latestRelease = getLatestRelease($game);
39     writeJson(
40         'api/v1/apps/' . $latestRelease->uuid . '.json',
41         buildApps($game)
42     );
43
44     writeJson(
45         'api/v1/apps/' . $latestRelease->uuid . '-download.json',
46         buildAppDownload($game, $latestRelease)
47     );
48     //exit(2);
49
50 }
51
52 writeJson('api/v1/discover.json', buildDiscover($games));
53 writeJson('api/v1/discover-data/home.json', buildDiscoverHome($games));
54
55 /**
56  * Build api/v1/apps/$package
57  */
58 function buildApps($game)
59 {
60     $latestRelease = getLatestRelease($game);
61
62     // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-apps-xxx
63     return [
64         'app' => [
65             'uuid'          => $game->uuid,
66             'title'         => $game->title,
67             'overview'      => $game->overview,
68             'description'   => $game->description,
69             'gamerNumbers'  => $game->players,
70             'genres'        => $game->genres,
71
72             'website'       => $game->website,
73             'contentRating' => $game->contentRating,
74             'premium'       => $game->premium,
75             'firstPublishedAt' => $game->firstPublishedAt,
76
77             'likeCount'     => $game->rating->likeCount,
78             'ratingAverage' => $game->rating->average,
79             'ratingCount'   => $game->rating->count,
80
81             'versionNumber' => $latestRelease->name,
82             'latestVersion' => $latestRelease->uuid,
83             'md5sum'        => $latestRelease->md5sum,
84             'apkFileSize'   => $latestRelease->size,
85             'publishedAt'   => $latestRelease->date,
86             'publicSize'    => $latestRelease->publicSize,
87             'nativeSize'    => $latestRelease->nativeSize,
88
89             'mainImageFullUrl' => $game->media->large,
90             'videoUrl'         => $game->media->video,
91             'filepickerScreenshots' => $game->media->screenshots,
92             'mobileAppIcon'    => null,
93
94             'developer'           => $game->developer->name,
95             'supportEmailAddress' => $game->developer->supportEmail,
96             'supportPhone'        => $game->developer->supportPhone,
97             'founder'             => $game->developer->founder,
98
99             'promotedProduct' => null,
100         ],
101     ];
102 }
103
104 function buildAppDownload($game, $release)
105 {
106     return [
107         'app' => [
108             'fileSize'      => $release->size,
109             'version'       => $release->uuid,
110             'contentRating' => $game->contentRating,
111             'downloadLink'  => $release->url,
112         ]
113     ];
114 }
115
116 /**
117  * Build /app/v1/details?app=org.example.game
118  */
119 function buildDetails($game)
120 {
121     $latestRelease = getLatestRelease($game);
122
123     $mediaTiles = [];
124     if ($game->media->large) {
125         $mediaTiles[] = [
126             'type' => 'image',
127             'urls' => [
128                 'thumbnail' => $game->media->large,
129                 'full'      => $game->media->large,
130             ],
131             'fp_url' => $game->media->large,
132         ];
133     }
134     if ($game->media->video) {
135         $mediaTiles[] = [
136             'type' => 'video',
137             'url'  => $game->media->video,
138         ];
139     }
140     foreach ($game->media->screenshots as $screenshot) {
141         $mediaTiles[] = [
142             'type' => 'image',
143             'urls' => [
144                 'thumbnail' => $screenshot,
145                 'full'      => $screenshot,
146             ],
147             'fp_url' => $screenshot,
148         ];
149     }
150
151     // http://cweiske.de/ouya-store-api-docs.htm#get-https-devs-ouya-tv-api-v1-details
152     return [
153         'type'             => 'Game',
154         'title'            => $game->title,
155         'description'      => $game->description,
156         'gamerNumbers'     => $game->players,
157         'genres'           => $game->genres,
158
159         'suggestedAge'     => $game->contentRating,
160         'premium'          => $game->premium,
161         'inAppPurchases'   => $game->inAppPurchases,
162         'firstPublishedAt' => strtotime($game->firstPublishedAt),
163         'ccUrl'            => null,
164
165         'rating' => [
166             'count'   => $game->rating->count,
167             'average' => $game->rating->average,
168         ],
169
170         'apk' => [
171             'fileSize'    => $latestRelease->size,
172             'nativeSize'  => $latestRelease->nativeSize,
173             'publicSize'  => $latestRelease->publicSize,
174             'md5sum'      => $latestRelease->md5sum,
175             'filename'    => 'FIXME',
176             'errors'      => '',
177             'package'     => $game->package,
178             'versionCode' => $latestRelease->versionCode,
179             'state'       => 'complete',
180         ],
181
182         'version' => [
183             'number'      => $latestRelease->name,
184             'publishedAt' => strtotime($latestRelease->date),
185             'uuid'        => $latestRelease->uuid,
186         ],
187
188         'developer' => [
189             'name'    => $game->developer->name,
190             'founder' => $game->developer->founder,
191         ],
192
193         'metaData' => [
194             'key:rating.average',
195             'key:developer.name',
196             'key:suggestedAge',
197             number_format($latestRelease->size / 1024 / 1024, 2, '.', '') . ' MiB',
198         ],
199
200         'tileImage'     => $game->media->discover,
201         'mediaTiles'    => $mediaTiles,
202         'mobileAppIcon' => null,
203         'heroImage'     => [
204             'url' => null,
205         ],
206
207         'promotedProduct' => null,
208     ];
209 }
210
211 function buildDiscover(array $games)
212 {
213     $data = [
214         'title' => 'DISCOVER',
215         'rows'  => [],
216         'tiles' => [],
217     ];
218     $tileMap = [];
219
220     $rowAll = [
221         'title'     => 'ALL GAMES',
222         'showPrice' => false,
223         'ranked'    => false,
224         'tiles'     => [],
225     ];
226     foreach ($games as $game) {
227         $tilePos = count($tileMap);
228         $data['tiles'][$tilePos] = buildDiscoverGameTile($game);
229         $tileMap[$game->package] = $tilePos;
230
231         $rowAll['tiles'][] = $tilePos;
232     }
233     $data['rows'][] = $rowAll;
234
235     return $data;
236 }
237
238 function buildDiscoverHome(array $games)
239 {
240     //we do not want anything here for now
241     $data = [
242         'title' => 'home',
243         'rows'  => [
244             [
245                 'title' => 'FEATURED',
246                 'showPrice' => false,
247                 'ranked'    => false,
248                 'tiles'     => [],
249             ]
250         ],
251         'tiles' => [],
252     ];
253     return $data;
254 }
255
256 function buildDiscoverGameTile($game)
257 {
258     $latestRelease = getLatestRelease($game);
259     return [
260         'gamerNumbers' => $game->players,
261         'genres' => $game->genres,
262         'url' => 'ouya://launcher/details?app=' . $game->package,
263         'latestVersion' => [
264             'apk' => [
265                 'md5sum' => $latestRelease->md5sum,
266             ],
267             'versionNumber' => $latestRelease->name,
268             'uuid' => $latestRelease->uuid,
269         ],
270         'inAppPurchases' => $game->inAppPurchases,
271         'promotedProduct' => null,
272         'premium' => $game->premium,
273         'type' => 'app',
274         'package' => $game->package,
275         'updated_at' => strtotime($latestRelease->date),
276         'updatedAt' => $latestRelease->date,
277         'title' => $game->title,
278         'image' => $game->media->discover,
279         'contentRating' => $game->contentRating,
280         'rating' => [
281             'count' => $game->rating->count,
282             'average' => $game->rating->average,
283         ],
284     ];
285 }
286
287 function addMissingGameProperties($game)
288 {
289     if (!isset($game->overview)) {
290         $game->overview = null;
291     }
292     if (!isset($game->description)) {
293         $game->description = '';
294     }
295     if (!isset($game->players)) {
296         $game->players = [1];
297     }
298     if (!isset($game->genres)) {
299         $game->genres = ['Unsorted'];
300     }
301     if (!isset($game->website)) {
302         $game->website = null;
303     }
304     if (!isset($game->contentRating)) {
305         $game->contentRating = 'Everyone';
306     }
307     if (!isset($game->premium)) {
308         $game->premium = false;
309     }
310     if (!isset($game->firstPublishedAt)) {
311         $game->firstPublishedAt = gmdate('c');
312     }
313
314     if (!isset($game->rating)) {
315         $game->rating = new stdClass();
316     }
317     if (!isset($game->rating->likeCount)) {
318         $game->rating->likeCount = 0;
319     }
320     if (!isset($game->rating->average)) {
321         $game->rating->average = 0;
322     }
323     if (!isset($game->rating->count)) {
324         $game->rating->count = 0;
325     }
326
327     foreach ($game->releases as $release) {
328         if (!isset($release->publicSize)) {
329             $release->publicSize = 0;
330         }
331         if (!isset($release->nativeSize)) {
332             $release->nativeSize = 0;
333         }
334     }
335
336     if (!isset($game->media->video)) {
337         $game->media->video = null;
338     }
339     if (!isset($game->media->screenshots)) {
340         $game->media->screenshots = [];
341     }
342     if (!isset($game->developer->uuid)) {
343         $game->developer->uuid = null;
344     }
345     if (!isset($game->developer->name)) {
346         $game->developer->name = 'unknown';
347     }
348     if (!isset($game->developer->supportEmail)) {
349         $game->developer->supportEmail = null;
350     }
351     if (!isset($game->developer->supportPhone)) {
352         $game->developer->supportPhone = null;
353     }
354     if (!isset($game->developer->founder)) {
355         $game->developer->founder = false;
356     }
357 }
358
359 function getLatestRelease($game)
360 {
361     $latestRelease = null;
362     foreach ($game->releases as $release) {
363         if ($release->latest ?? false) {
364             $latestRelease = $release;
365             break;
366         }
367     }
368     if ($latestRelease === null) {
369         error('No latest release for ' . $game->package);
370     }
371     return $latestRelease;
372 }
373
374 function writeJson($path, $data)
375 {
376     global $wwwDir;
377     $fullPath = $wwwDir . $path;
378     $dir = dirname($fullPath);
379     if (!is_dir($dir)) {
380         mkdir($dir, 0777, true);
381     }
382     file_put_contents(
383         $fullPath,
384         json_encode($data, JSON_PRETTY_PRINT) . "\n"
385     );
386 }
387
388 function error($msg)
389 {
390     fwrite(STDERR, $msg . "\n");
391     exit(1);
392 }
393 ?>