loadPlayMetadata function
Loads the Play metadata tree at path.
Throws MetadataException — shared with the App Store side, because a caller checking both wants one exception type and one message style.
Implementation
PlayMetadata loadPlayMetadata(String path) {
final root = Directory(path);
if (!root.existsSync()) {
throw MetadataException('$path does not exist');
}
final metadata = PlayMetadata(path);
final defaultLanguage = File('$path/details/default_language.txt');
if (defaultLanguage.existsSync()) {
final value = defaultLanguage.readAsStringSync().trim();
metadata.defaultLanguage = value.isEmpty ? null : value;
}
final listings = Directory('$path/listings');
if (!listings.existsSync()) {
throw MetadataException(
'$path has no listings/ directory — a Play tree keeps each locale in '
'listings/<bcp-47>/',
);
}
final localeDirs = listings.listSync().whereType<Directory>().toList()
..sort((a, b) => a.path.compareTo(b.path));
for (final dir in localeDirs) {
final locale = dir.path.split(Platform.pathSeparator).last;
final entry = PlayLocaleMetadata(locale);
for (final field in playListingLimits.keys) {
final file = File('${dir.path}/$field.txt');
if (file.existsSync()) {
// Trailing newline removed and nothing else: a text file ends with one
// and Play does not store it, but stripping any further would be the
// normalisation this file's header warns about.
entry.text[field] = _withoutTrailingNewline(file.readAsStringSync());
}
}
final images = Directory('${dir.path}/images');
if (images.existsSync()) {
final imageDirs = images.listSync().whereType<Directory>().toList()
..sort((a, b) => a.path.compareTo(b.path));
for (final imageDir in imageDirs) {
final name = imageDir.path.split(Platform.pathSeparator).last;
final files =
imageDir
.listSync()
.whereType<File>()
.where((f) => _isImage(f.path))
.toList()
..sort((a, b) => a.path.compareTo(b.path));
entry.images[name] = files;
}
}
metadata.locales.add(entry);
}
return metadata;
}