import 'dart:convert';
import 'package:html/parser.dart' as html_parser;
import 'package:http/http.dart' as http;
class ScrapedRecipe {
final String title;
final List ingredients;
final List instructions;
final double? proteinGrams;
ScrapedRecipe({
required this.title,
required this.ingredients,
required this.instructions,
this.proteinGrams,
});
}
class RecipeScraperService {
Future extractFromUrl(String url) async {
final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) return null;
final document = html_parser.parse(response.body);
final scriptTags =
document.querySelectorAll('script[type="application/ld+json"]');
for (final tag in scriptTags) {
try {
final data = jsonDecode(tag.text);
if (data is Map && data['@type'] == 'Recipe') {
return _parseJsonLd(data);
} else if (data is List) {
final recipe = data.firstWhere((e) => e['@type'] == 'Recipe',
orElse: () => null);
if (recipe != null) return _parseJsonLd(recipe);
}
} catch (_) {
continue;
}
}
return null;
}
ScrapedRecipe _parseJsonLd(Map json) {
return ScrapedRecipe(
title: json['name'] ?? 'Untitled Recipe',
ingredients: List.from(json['recipeIngredient'] ?? []),
instructions: (json['recipeInstructions'] as List? ?? [])
.map((step) =>
step is Map ? step['text']?.toString() ?? '' : step.toString())
.toList(),
proteinGrams: double.tryParse(
json['nutrition']?['proteinContent']
?.toString()
.replaceAll(RegExp(r'[^0-9.]'), '') ??
'',
),
);
}
}