searchTitles method
Implementation
Future<List<LibrivoxItem>> searchTitles({
required String query,
int page = 1,
int rows = 10,
}) async {
try {
// Validate input parameters
if (query.trim().isEmpty) {
throw ArgumentError('Query cannot be empty');
}
if (page < 1) {
throw ArgumentError('Page must be greater than 0');
}
if (rows < 1 || rows > 1000) {
throw ArgumentError('Rows must be between 1 and 1000');
}
final uri = Uri.parse(_baseUrl).replace(
queryParameters: {
'q': 'collection:(librivoxaudio) AND title:($query)',
// 'fl[]': 'identifier',
// 'fl[]': 'title',
// 'fl[]': 'creator',
'rows': rows.toString(),
'page': page.toString(),
'output': 'json',
},
);
final response = await http.get(uri);
if (response.statusCode == 404) {
throw LibrivoxNotFoundException('No results found for query: $query');
}
if (response.statusCode != 200) {
throw LibrivoxApiException(
'Failed to fetch Librivox titles. Status: ${response.statusCode}',
);
}
final Map<String, dynamic> jsonMap;
try {
jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
} catch (e) {
throw LibrivoxParseException('Failed to parse response: $e');
}
final responseData = jsonMap['response'] as Map<String, dynamic>?;
if (responseData == null) {
throw const LibrivoxParseException(
'Invalid response format: missing response field',
);
}
final docs = (responseData['docs'] as List<dynamic>?) ?? [];
return docs.map((doc) {
try {
final docmap = doc as Map<String, dynamic>;
// Validate required fields
final identifier = docmap['identifier'] as String?;
final title = docmap['title'] as String?;
if (identifier == null || identifier.isEmpty) {
throw const LibrivoxParseException(
'Missing or empty identifier in response',
);
}
if (title == null || title.isEmpty) {
throw const LibrivoxParseException(
'Missing or empty title in response',
);
}
return LibrivoxItem(
id: identifier,
title: title,
author: docmap.containsKey('creator')
? docmap['creator'] as String?
: null,
// releaseDate: docmap.containsKey('date')
// ? docmap['date'] as String
// : null,
// description: docmap.containsKey('description')
// ? docmap['description'] as String
// : null,
language: docmap.containsKey('language')
? docmap['language'] as String?
: null,
coverUrl: 'https://archive.org/services/img/$identifier',
);
} catch (e) {
// Skip malformed items but log the error
throw LibrivoxParseException('Failed to parse item: $e');
}
}).toList();
} catch (e) {
throw LibrivoxApiException('Unexpected error occurred: $e');
}
}